fix: add involves edge from task to agent:nomos at creation
Plus sync vendor directory for Docker build compatibility.
This commit is contained in:
469
vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
Normal file
469
vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
# Changes
|
||||||
|
|
||||||
|
## [0.18.1](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.18.1) (2026-01-21)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add InternalOptions.TelemetryAttributes for internal client use (#13641) ([3876978](https://github.com/googleapis/google-cloud-go/commit/38769789755ed47d85e85dcd56596109de65f780))
|
||||||
|
* remove singleton and restore normal usage of otelgrpc.clientHandler (#13522) ([673d4b0](https://github.com/googleapis/google-cloud-go/commit/673d4b05617f833aa433f7f6a350b5cb888ea20d))
|
||||||
|
|
||||||
|
## [0.18.0](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.18.0) (2025-12-15)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Support scopes field from impersonated credential json (#13308) ([e3f62e1](https://github.com/googleapis/google-cloud-go/commit/e3f62e102840127a0058f5cced4c9738f2bf45f2))
|
||||||
|
* add support for parsing EC private key (#13317) ([ea6bc62](https://github.com/googleapis/google-cloud-go/commit/ea6bc62ffe2cc0a6d607d698a181b37fa46c340d))
|
||||||
|
* deprecate unsafe credentials JSON loading options (#13397) ([0dd2a3b](https://github.com/googleapis/google-cloud-go/commit/0dd2a3bdece9a85ee7216a737559fa9f5a869545))
|
||||||
|
|
||||||
|
## [0.17.0](https://github.com/googleapis/google-cloud-go/releases/tag/auth%2Fv0.17.0) (2025-10-02)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add trust boundary support for service accounts and impersonation (HTTP/gRPC) (#11870) ([5c2b665](https://github.com/googleapis/google-cloud-go/commit/5c2b665f392e6dd90192f107188720aa1357e7da))
|
||||||
|
* add trust boundary support for external accounts (#12864) ([a67a146](https://github.com/googleapis/google-cloud-go/commit/a67a146a6a88a6f1ba10c409dfce8015ecd60a64))
|
||||||
|
|
||||||
|
## [0.16.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.4...auth/v0.16.5) (2025-08-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Improve error message for unknown credentials type ([#12673](https://github.com/googleapis/google-cloud-go/issues/12673)) ([558b164](https://github.com/googleapis/google-cloud-go/commit/558b16429f621276694405fa5f2091199f2d4c4d))
|
||||||
|
* **auth:** Set Content-Type in userTokenProvider.exchangeToken ([#12634](https://github.com/googleapis/google-cloud-go/issues/12634)) ([1197ebc](https://github.com/googleapis/google-cloud-go/commit/1197ebcbca491f8c610da732c7361c90bc6f46d0))
|
||||||
|
|
||||||
|
## [0.16.4](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.3...auth/v0.16.4) (2025-08-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Add UseDefaultClient: true to metadata.Options ([#12666](https://github.com/googleapis/google-cloud-go/issues/12666)) ([1482191](https://github.com/googleapis/google-cloud-go/commit/1482191e88236693efef68769752638281566766)), refs [#11078](https://github.com/googleapis/google-cloud-go/issues/11078) [#12657](https://github.com/googleapis/google-cloud-go/issues/12657)
|
||||||
|
|
||||||
|
## [0.16.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.2...auth/v0.16.3) (2025-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Fix race condition in cachedTokenProvider.tokenAsync ([#12586](https://github.com/googleapis/google-cloud-go/issues/12586)) ([73867cc](https://github.com/googleapis/google-cloud-go/commit/73867ccc1e9808d65361bcfc0776bd95fe34dbb3))
|
||||||
|
|
||||||
|
## [0.16.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.1...auth/v0.16.2) (2025-06-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Add back DirectPath misconfiguration logging ([#11162](https://github.com/googleapis/google-cloud-go/issues/11162)) ([8d52da5](https://github.com/googleapis/google-cloud-go/commit/8d52da58da5a0ed77a0f6307d1b561bc045406a1))
|
||||||
|
* **auth:** Remove s2a fallback option ([#12354](https://github.com/googleapis/google-cloud-go/issues/12354)) ([d5acc59](https://github.com/googleapis/google-cloud-go/commit/d5acc599cd775ddc404349e75906fa02e8ff133e))
|
||||||
|
|
||||||
|
## [0.16.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.16.0...auth/v0.16.1) (2025-04-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Clone detectopts before assigning TokenBindingType ([#11881](https://github.com/googleapis/google-cloud-go/issues/11881)) ([2167b02](https://github.com/googleapis/google-cloud-go/commit/2167b020fdc43b517c2b6ecca264a10e357ea035))
|
||||||
|
|
||||||
|
## [0.16.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.15.0...auth/v0.16.0) (2025-04-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth/credentials:** Return X.509 certificate chain as subject token ([#11948](https://github.com/googleapis/google-cloud-go/issues/11948)) ([d445a3f](https://github.com/googleapis/google-cloud-go/commit/d445a3f66272ffd5c39c4939af9bebad4582631c)), refs [#11757](https://github.com/googleapis/google-cloud-go/issues/11757)
|
||||||
|
* **auth:** Configure DirectPath bound credentials from AllowedHardBoundTokens ([#11665](https://github.com/googleapis/google-cloud-go/issues/11665)) ([0fc40bc](https://github.com/googleapis/google-cloud-go/commit/0fc40bcf4e4673704df0973e9fa65957395d7bb4))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Allow non-default SA credentials for DP ([#11828](https://github.com/googleapis/google-cloud-go/issues/11828)) ([3a996b4](https://github.com/googleapis/google-cloud-go/commit/3a996b4129e6d0a34dfda6671f535d5aefb26a82))
|
||||||
|
* **auth:** Restore calling DialContext ([#11930](https://github.com/googleapis/google-cloud-go/issues/11930)) ([9ec9a29](https://github.com/googleapis/google-cloud-go/commit/9ec9a29494e93197edbaf45aba28984801e9770a)), refs [#11118](https://github.com/googleapis/google-cloud-go/issues/11118)
|
||||||
|
|
||||||
|
## [0.15.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.14.1...auth/v0.15.0) (2025-02-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add hard-bound token request to compute token provider. ([#11588](https://github.com/googleapis/google-cloud-go/issues/11588)) ([0e608bb](https://github.com/googleapis/google-cloud-go/commit/0e608bb5ac3d694c8ad36ca4340071d3a2c78699))
|
||||||
|
|
||||||
|
## [0.14.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.14.0...auth/v0.14.1) (2025-01-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
* **auth:** Add warning about externally-provided credentials ([#11462](https://github.com/googleapis/google-cloud-go/issues/11462)) ([49fb6ff](https://github.com/googleapis/google-cloud-go/commit/49fb6ff4d754895f82c9c4d502fc7547d3b5a941))
|
||||||
|
|
||||||
|
## [0.14.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.13.0...auth/v0.14.0) (2025-01-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add universe domain support to idtoken ([#11059](https://github.com/googleapis/google-cloud-go/issues/11059)) ([72add7e](https://github.com/googleapis/google-cloud-go/commit/72add7e9f8f455af695e8ef79212a4bd3122fb3a))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
||||||
|
* **auth:** Fix copy of delegates in impersonate.NewIDTokenCredentials ([#11386](https://github.com/googleapis/google-cloud-go/issues/11386)) ([ff7ef8e](https://github.com/googleapis/google-cloud-go/commit/ff7ef8e7ade7171bce3e4f30ff10a2e9f6c27ca0)), refs [#11379](https://github.com/googleapis/google-cloud-go/issues/11379)
|
||||||
|
* **auth:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
||||||
|
|
||||||
|
## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.1...auth/v0.13.0) (2024-12-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add logging support ([#11079](https://github.com/googleapis/google-cloud-go/issues/11079)) ([c80e31d](https://github.com/googleapis/google-cloud-go/commit/c80e31df5ecb33a810be3dfb9d9e27ac531aa91d))
|
||||||
|
* **auth:** Pass logger from auth layer to metadata package ([#11288](https://github.com/googleapis/google-cloud-go/issues/11288)) ([b552efd](https://github.com/googleapis/google-cloud-go/commit/b552efd6ab34e5dfded18438e0fbfd925805614f))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Check compute cred type before non-default flag for DP ([#11255](https://github.com/googleapis/google-cloud-go/issues/11255)) ([4347ca1](https://github.com/googleapis/google-cloud-go/commit/4347ca141892be8ae813399b4b437662a103bc90))
|
||||||
|
|
||||||
|
## [0.12.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.0...auth/v0.12.1) (2024-12-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Correct typo in link ([#11160](https://github.com/googleapis/google-cloud-go/issues/11160)) ([af6fb46](https://github.com/googleapis/google-cloud-go/commit/af6fb46d7cd694ddbe8c9d63bc4cdcd62b9fb2c1))
|
||||||
|
|
||||||
|
## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.11.0...auth/v0.12.0) (2024-12-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add support for providing custom certificate URL ([#11006](https://github.com/googleapis/google-cloud-go/issues/11006)) ([ebf3657](https://github.com/googleapis/google-cloud-go/commit/ebf36579724afb375d3974cf1da38f703e3b7dbc)), refs [#11005](https://github.com/googleapis/google-cloud-go/issues/11005)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Ensure endpoints are present in Validator ([#11209](https://github.com/googleapis/google-cloud-go/issues/11209)) ([106cd53](https://github.com/googleapis/google-cloud-go/commit/106cd53309facaef1b8ea78376179f523f6912b9)), refs [#11006](https://github.com/googleapis/google-cloud-go/issues/11006) [#11190](https://github.com/googleapis/google-cloud-go/issues/11190) [#11189](https://github.com/googleapis/google-cloud-go/issues/11189) [#11188](https://github.com/googleapis/google-cloud-go/issues/11188)
|
||||||
|
|
||||||
|
## [0.11.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.2...auth/v0.11.0) (2024-11-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add universe domain support to mTLS ([#11159](https://github.com/googleapis/google-cloud-go/issues/11159)) ([117748b](https://github.com/googleapis/google-cloud-go/commit/117748ba1cfd4ae62a6a4feb7e30951cb2bc9344))
|
||||||
|
|
||||||
|
## [0.10.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.1...auth/v0.10.2) (2024-11-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Restore use of grpc.Dial ([#11118](https://github.com/googleapis/google-cloud-go/issues/11118)) ([2456b94](https://github.com/googleapis/google-cloud-go/commit/2456b943b7b8aaabd4d8bfb7572c0f477ae0db45)), refs [#7556](https://github.com/googleapis/google-cloud-go/issues/7556)
|
||||||
|
|
||||||
|
## [0.10.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.0...auth/v0.10.1) (2024-11-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Restore Application Default Credentials support to idtoken ([#11083](https://github.com/googleapis/google-cloud-go/issues/11083)) ([8771f2e](https://github.com/googleapis/google-cloud-go/commit/8771f2ea9807ab822083808e0678392edff3b4f2))
|
||||||
|
* **auth:** Skip impersonate universe domain check if empty ([#11086](https://github.com/googleapis/google-cloud-go/issues/11086)) ([87159c1](https://github.com/googleapis/google-cloud-go/commit/87159c1059d4a18d1367ce62746a838a94964ab6))
|
||||||
|
|
||||||
|
## [0.10.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.9...auth/v0.10.0) (2024-10-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add universe domain support to credentials/impersonate ([#10953](https://github.com/googleapis/google-cloud-go/issues/10953)) ([e06cb64](https://github.com/googleapis/google-cloud-go/commit/e06cb6499f7eda3aef08ab18ff197016f667684b))
|
||||||
|
|
||||||
|
## [0.9.9](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.8...auth/v0.9.9) (2024-10-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Fallback cert lookups for missing files ([#11013](https://github.com/googleapis/google-cloud-go/issues/11013)) ([bd76695](https://github.com/googleapis/google-cloud-go/commit/bd766957ec238b7c40ddbabb369e612dc9b07313)), refs [#10844](https://github.com/googleapis/google-cloud-go/issues/10844)
|
||||||
|
* **auth:** Replace MDS endpoint universe_domain with universe-domain ([#11000](https://github.com/googleapis/google-cloud-go/issues/11000)) ([6a1586f](https://github.com/googleapis/google-cloud-go/commit/6a1586f2ce9974684affaea84e7b629313b4d114))
|
||||||
|
|
||||||
|
## [0.9.8](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.7...auth/v0.9.8) (2024-10-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Restore OpenTelemetry handling in transports ([#10968](https://github.com/googleapis/google-cloud-go/issues/10968)) ([08c6d04](https://github.com/googleapis/google-cloud-go/commit/08c6d04901c1a20e219b2d86df41dbaa6d7d7b55)), refs [#10962](https://github.com/googleapis/google-cloud-go/issues/10962)
|
||||||
|
* **auth:** Try talk to plaintext S2A if credentials can not be found for mTLS-S2A ([#10941](https://github.com/googleapis/google-cloud-go/issues/10941)) ([0f0bf2d](https://github.com/googleapis/google-cloud-go/commit/0f0bf2d18c97dd8b65bcf0099f0802b5631c6287))
|
||||||
|
|
||||||
|
## [0.9.7](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.6...auth/v0.9.7) (2024-10-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Restore support for non-default service accounts for DirectPath ([#10937](https://github.com/googleapis/google-cloud-go/issues/10937)) ([a38650e](https://github.com/googleapis/google-cloud-go/commit/a38650edbf420223077498cafa537aec74b37aad)), refs [#10907](https://github.com/googleapis/google-cloud-go/issues/10907)
|
||||||
|
|
||||||
|
## [0.9.6](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.5...auth/v0.9.6) (2024-09-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Make aws credentials provider retrieve fresh credentials ([#10920](https://github.com/googleapis/google-cloud-go/issues/10920)) ([250fbf8](https://github.com/googleapis/google-cloud-go/commit/250fbf87d858d865e399a241b7e537c4ff0c3dd8))
|
||||||
|
|
||||||
|
## [0.9.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.4...auth/v0.9.5) (2024-09-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Restore support for GOOGLE_CLOUD_UNIVERSE_DOMAIN env ([#10915](https://github.com/googleapis/google-cloud-go/issues/10915)) ([94caaaa](https://github.com/googleapis/google-cloud-go/commit/94caaaa061362d0e00ef6214afcc8a0a3e7ebfb2))
|
||||||
|
* **auth:** Skip directpath credentials overwrite when it's not on GCE ([#10833](https://github.com/googleapis/google-cloud-go/issues/10833)) ([7e5e8d1](https://github.com/googleapis/google-cloud-go/commit/7e5e8d10b761b0a6e43e19a028528db361bc07b1))
|
||||||
|
* **auth:** Use new context for non-blocking token refresh ([#10919](https://github.com/googleapis/google-cloud-go/issues/10919)) ([cf7102d](https://github.com/googleapis/google-cloud-go/commit/cf7102d33a21be1e5a9d47a49456b3a57c43b350))
|
||||||
|
|
||||||
|
## [0.9.4](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.3...auth/v0.9.4) (2024-09-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Enable self-signed JWT for non-GDU universe domain ([#10831](https://github.com/googleapis/google-cloud-go/issues/10831)) ([f9869f7](https://github.com/googleapis/google-cloud-go/commit/f9869f7903cfd34d1b97c25d0dc5669d2c5138e6))
|
||||||
|
|
||||||
|
## [0.9.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.2...auth/v0.9.3) (2024-09-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Choose quota project envvar over file when both present ([#10807](https://github.com/googleapis/google-cloud-go/issues/10807)) ([2d8dd77](https://github.com/googleapis/google-cloud-go/commit/2d8dd7700eff92d4b95027be55e26e1e7aa79181)), refs [#10804](https://github.com/googleapis/google-cloud-go/issues/10804)
|
||||||
|
|
||||||
|
## [0.9.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.1...auth/v0.9.2) (2024-08-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Handle non-Transport DefaultTransport ([#10733](https://github.com/googleapis/google-cloud-go/issues/10733)) ([98d91dc](https://github.com/googleapis/google-cloud-go/commit/98d91dc8316b247498fab41ab35e57a0446fe556)), refs [#10742](https://github.com/googleapis/google-cloud-go/issues/10742)
|
||||||
|
* **auth:** Make sure quota option takes precedence over env/file ([#10797](https://github.com/googleapis/google-cloud-go/issues/10797)) ([f1b050d](https://github.com/googleapis/google-cloud-go/commit/f1b050d56d804b245cab048c2980d32b0eaceb4e)), refs [#10795](https://github.com/googleapis/google-cloud-go/issues/10795)
|
||||||
|
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
* **auth:** Fix Go doc comment link ([#10751](https://github.com/googleapis/google-cloud-go/issues/10751)) ([015acfa](https://github.com/googleapis/google-cloud-go/commit/015acfab4d172650928bb1119bc2cd6307b9a437))
|
||||||
|
|
||||||
|
## [0.9.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.0...auth/v0.9.1) (2024-08-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Setting expireEarly to default when the value is 0 ([#10732](https://github.com/googleapis/google-cloud-go/issues/10732)) ([5e67869](https://github.com/googleapis/google-cloud-go/commit/5e67869a31e9e8ecb4eeebd2cfa11a761c3b1948))
|
||||||
|
|
||||||
|
## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.8.1...auth/v0.9.0) (2024-08-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Auth library can talk to S2A over mTLS ([#10634](https://github.com/googleapis/google-cloud-go/issues/10634)) ([5250a13](https://github.com/googleapis/google-cloud-go/commit/5250a13ec95b8d4eefbe0158f82857ff2189cb45))
|
||||||
|
|
||||||
|
## [0.8.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.8.0...auth/v0.8.1) (2024-08-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Make default client creation more lenient ([#10669](https://github.com/googleapis/google-cloud-go/issues/10669)) ([1afb9ee](https://github.com/googleapis/google-cloud-go/commit/1afb9ee1ee9de9810722800018133304a0ca34d1)), refs [#10638](https://github.com/googleapis/google-cloud-go/issues/10638)
|
||||||
|
|
||||||
|
## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.3...auth/v0.8.0) (2024-08-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Adds support for X509 workload identity federation ([#10373](https://github.com/googleapis/google-cloud-go/issues/10373)) ([5d07505](https://github.com/googleapis/google-cloud-go/commit/5d075056cbe27bb1da4072a26070c41f8999eb9b))
|
||||||
|
|
||||||
|
## [0.7.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.2...auth/v0.7.3) (2024-08-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
* **auth:** Disable automatic universe domain check for MDS ([#10620](https://github.com/googleapis/google-cloud-go/issues/10620)) ([7cea5ed](https://github.com/googleapis/google-cloud-go/commit/7cea5edd5a0c1e6bca558696f5607879141910e8))
|
||||||
|
* **auth:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
|
||||||
|
## [0.7.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.1...auth/v0.7.2) (2024-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Use default client for universe metadata lookup ([#10551](https://github.com/googleapis/google-cloud-go/issues/10551)) ([d9046fd](https://github.com/googleapis/google-cloud-go/commit/d9046fdd1435d1ce48f374806c1def4cb5ac6cd3)), refs [#10544](https://github.com/googleapis/google-cloud-go/issues/10544)
|
||||||
|
|
||||||
|
## [0.7.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.0...auth/v0.7.1) (2024-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Bump google.golang.org/grpc@v1.64.1 ([8ecc4e9](https://github.com/googleapis/google-cloud-go/commit/8ecc4e9622e5bbe9b90384d5848ab816027226c5))
|
||||||
|
|
||||||
|
## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.6.1...auth/v0.7.0) (2024-07-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add workload X509 cert provider as a default cert provider ([#10479](https://github.com/googleapis/google-cloud-go/issues/10479)) ([c51ee6c](https://github.com/googleapis/google-cloud-go/commit/c51ee6cf65ce05b4d501083e49d468c75ac1ea63))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
||||||
|
* **auth:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
||||||
|
* **auth:** Check len of slices, not non-nil ([#10483](https://github.com/googleapis/google-cloud-go/issues/10483)) ([0a966a1](https://github.com/googleapis/google-cloud-go/commit/0a966a183e5f0e811977216d736d875b7233e942))
|
||||||
|
|
||||||
|
## [0.6.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.6.0...auth/v0.6.1) (2024-07-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Support gRPC API keys ([#10460](https://github.com/googleapis/google-cloud-go/issues/10460)) ([daa6646](https://github.com/googleapis/google-cloud-go/commit/daa6646d2af5d7fb5b30489f4934c7db89868c7c))
|
||||||
|
* **auth:** Update http and grpc transports to support token exchange over mTLS ([#10397](https://github.com/googleapis/google-cloud-go/issues/10397)) ([c6dfdcf](https://github.com/googleapis/google-cloud-go/commit/c6dfdcf893c3f971eba15026c12db0a960ae81f2))
|
||||||
|
|
||||||
|
## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.2...auth/v0.6.0) (2024-06-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add non-blocking token refresh for compute MDS ([#10263](https://github.com/googleapis/google-cloud-go/issues/10263)) ([9ac350d](https://github.com/googleapis/google-cloud-go/commit/9ac350da11a49b8e2174d3fc5b1a5070fec78b4e))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Return error if envvar detected file returns an error ([#10431](https://github.com/googleapis/google-cloud-go/issues/10431)) ([e52b9a7](https://github.com/googleapis/google-cloud-go/commit/e52b9a7c45468827f5d220ab00965191faeb9d05))
|
||||||
|
|
||||||
|
## [0.5.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.1...auth/v0.5.2) (2024-06-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Fetch initial token when CachedTokenProviderOptions.DisableAutoRefresh is true ([#10415](https://github.com/googleapis/google-cloud-go/issues/10415)) ([3266763](https://github.com/googleapis/google-cloud-go/commit/32667635ca2efad05cd8c087c004ca07d7406913)), refs [#10414](https://github.com/googleapis/google-cloud-go/issues/10414)
|
||||||
|
|
||||||
|
## [0.5.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.5.0...auth/v0.5.1) (2024-05-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Pass through client to 2LO and 3LO flows ([#10290](https://github.com/googleapis/google-cloud-go/issues/10290)) ([685784e](https://github.com/googleapis/google-cloud-go/commit/685784ea84358c15e9214bdecb307d37aa3b6d2f))
|
||||||
|
|
||||||
|
## [0.5.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.2...auth/v0.5.0) (2024-05-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Adds X509 workload certificate provider ([#10233](https://github.com/googleapis/google-cloud-go/issues/10233)) ([17a9db7](https://github.com/googleapis/google-cloud-go/commit/17a9db73af35e3d1a7a25ac4fd1377a103de6150))
|
||||||
|
|
||||||
|
## [0.4.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.1...auth/v0.4.2) (2024-05-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Enable client certificates by default only for GDU ([#10151](https://github.com/googleapis/google-cloud-go/issues/10151)) ([7c52978](https://github.com/googleapis/google-cloud-go/commit/7c529786275a39b7e00525f7d5e7be0d963e9e15))
|
||||||
|
* **auth:** Handle non-Transport DefaultTransport ([#10162](https://github.com/googleapis/google-cloud-go/issues/10162)) ([fa3bfdb](https://github.com/googleapis/google-cloud-go/commit/fa3bfdb23aaa45b34394a8b61e753b3587506782)), refs [#10159](https://github.com/googleapis/google-cloud-go/issues/10159)
|
||||||
|
* **auth:** Have refresh time match docs ([#10147](https://github.com/googleapis/google-cloud-go/issues/10147)) ([bcb5568](https://github.com/googleapis/google-cloud-go/commit/bcb5568c07a54dd3d2e869d15f502b0741a609e8))
|
||||||
|
* **auth:** Update compute token fetching error with named prefix ([#10180](https://github.com/googleapis/google-cloud-go/issues/10180)) ([4573504](https://github.com/googleapis/google-cloud-go/commit/4573504828d2928bebedc875d87650ba227829ea))
|
||||||
|
|
||||||
|
## [0.4.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.4.0...auth/v0.4.1) (2024-05-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Don't try to detect default creds it opt configured ([#10143](https://github.com/googleapis/google-cloud-go/issues/10143)) ([804632e](https://github.com/googleapis/google-cloud-go/commit/804632e7c5b0b85ff522f7951114485e256eb5bc))
|
||||||
|
|
||||||
|
## [0.4.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.3.0...auth/v0.4.0) (2024-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Enable client certificates by default ([#10102](https://github.com/googleapis/google-cloud-go/issues/10102)) ([9013e52](https://github.com/googleapis/google-cloud-go/commit/9013e5200a6ec0f178ed91acb255481ffb073a2c))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Get s2a logic up to date ([#10093](https://github.com/googleapis/google-cloud-go/issues/10093)) ([4fe9ae4](https://github.com/googleapis/google-cloud-go/commit/4fe9ae4b7101af2a5221d6d6b2e77b479305bb06))
|
||||||
|
|
||||||
|
## [0.3.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.2...auth/v0.3.0) (2024-04-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth/httptransport:** Add ability to customize transport ([#10023](https://github.com/googleapis/google-cloud-go/issues/10023)) ([72c7f6b](https://github.com/googleapis/google-cloud-go/commit/72c7f6bbec3136cc7a62788fc7186bc33ef6c3b3)), refs [#9812](https://github.com/googleapis/google-cloud-go/issues/9812) [#9814](https://github.com/googleapis/google-cloud-go/issues/9814)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/credentials:** Error on bad file name if explicitly set ([#10018](https://github.com/googleapis/google-cloud-go/issues/10018)) ([55beaa9](https://github.com/googleapis/google-cloud-go/commit/55beaa993aaf052d8be39766afc6777c3c2a0bdd)), refs [#9809](https://github.com/googleapis/google-cloud-go/issues/9809)
|
||||||
|
|
||||||
|
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.1...auth/v0.2.2) (2024-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Add internal opt to skip validation on transports ([#9999](https://github.com/googleapis/google-cloud-go/issues/9999)) ([9e20ef8](https://github.com/googleapis/google-cloud-go/commit/9e20ef89f6287d6bd03b8697d5898dc43b4a77cf)), refs [#9823](https://github.com/googleapis/google-cloud-go/issues/9823)
|
||||||
|
* **auth:** Set secure flag for gRPC conn pools ([#10002](https://github.com/googleapis/google-cloud-go/issues/10002)) ([14e3956](https://github.com/googleapis/google-cloud-go/commit/14e3956dfd736399731b5ee8d9b178ae085cf7ba)), refs [#9833](https://github.com/googleapis/google-cloud-go/issues/9833)
|
||||||
|
|
||||||
|
## [0.2.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.2.0...auth/v0.2.1) (2024-04-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** Default gRPC token type to Bearer if not set ([#9800](https://github.com/googleapis/google-cloud-go/issues/9800)) ([5284066](https://github.com/googleapis/google-cloud-go/commit/5284066670b6fe65d79089cfe0199c9660f87fc7))
|
||||||
|
|
||||||
|
## [0.2.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.1.1...auth/v0.2.0) (2024-04-15)
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
In the below mentioned commits there were a few large breaking changes since the
|
||||||
|
last release of the module.
|
||||||
|
|
||||||
|
1. The `Credentials` type has been moved to the root of the module as it is
|
||||||
|
becoming the core abstraction for the whole module.
|
||||||
|
2. Because of the above mentioned change many functions that previously
|
||||||
|
returned a `TokenProvider` now return `Credentials`. Similarly, these
|
||||||
|
functions have been renamed to be more specific.
|
||||||
|
3. Most places that used to take an optional `TokenProvider` now accept
|
||||||
|
`Credentials`. You can make a `Credentials` from a `TokenProvider` using the
|
||||||
|
constructor found in the `auth` package.
|
||||||
|
4. The `detect` package has been renamed to `credentials`. With this change some
|
||||||
|
function signatures were also updated for better readability.
|
||||||
|
5. Derivative auth flows like `impersonate` and `downscope` have been moved to
|
||||||
|
be under the new `credentials` package.
|
||||||
|
|
||||||
|
Although these changes are disruptive we think that they are for the best of the
|
||||||
|
long-term health of the module. We do not expect any more large breaking changes
|
||||||
|
like these in future revisions, even before 1.0.0. This version will be the
|
||||||
|
first version of the auth library that our client libraries start to use and
|
||||||
|
depend on.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth/credentials/externalaccount:** Add default TokenURL ([#9700](https://github.com/googleapis/google-cloud-go/issues/9700)) ([81830e6](https://github.com/googleapis/google-cloud-go/commit/81830e6848ceefd055aa4d08f933d1154455a0f6))
|
||||||
|
* **auth:** Add downscope.Options.UniverseDomain ([#9634](https://github.com/googleapis/google-cloud-go/issues/9634)) ([52cf7d7](https://github.com/googleapis/google-cloud-go/commit/52cf7d780853594291c4e34302d618299d1f5a1d))
|
||||||
|
* **auth:** Add universe domain to grpctransport and httptransport ([#9663](https://github.com/googleapis/google-cloud-go/issues/9663)) ([67d353b](https://github.com/googleapis/google-cloud-go/commit/67d353beefe3b607c08c891876fbd95ab89e5fe3)), refs [#9670](https://github.com/googleapis/google-cloud-go/issues/9670)
|
||||||
|
* **auth:** Add UniverseDomain to DetectOptions ([#9536](https://github.com/googleapis/google-cloud-go/issues/9536)) ([3618d3f](https://github.com/googleapis/google-cloud-go/commit/3618d3f7061615c0e189f376c75abc201203b501))
|
||||||
|
* **auth:** Make package externalaccount public ([#9633](https://github.com/googleapis/google-cloud-go/issues/9633)) ([a0978d8](https://github.com/googleapis/google-cloud-go/commit/a0978d8e96968399940ebd7d092539772bf9caac))
|
||||||
|
* **auth:** Move credentials to base auth package ([#9590](https://github.com/googleapis/google-cloud-go/issues/9590)) ([1a04baf](https://github.com/googleapis/google-cloud-go/commit/1a04bafa83c27342b9308d785645e1e5423ea10d))
|
||||||
|
* **auth:** Refactor public sigs to use Credentials ([#9603](https://github.com/googleapis/google-cloud-go/issues/9603)) ([69cb240](https://github.com/googleapis/google-cloud-go/commit/69cb240c530b1f7173a9af2555c19e9a1beb56c5))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
||||||
|
* **auth:** Fix uint32 conversion ([9221c7f](https://github.com/googleapis/google-cloud-go/commit/9221c7fa12cef9d5fb7ddc92f41f1d6204971c7b))
|
||||||
|
* **auth:** Port sts expires fix ([#9618](https://github.com/googleapis/google-cloud-go/issues/9618)) ([7bec97b](https://github.com/googleapis/google-cloud-go/commit/7bec97b2f51ed3ac4f9b88bf100d301da3f5d1bd))
|
||||||
|
* **auth:** Read universe_domain from all credentials files ([#9632](https://github.com/googleapis/google-cloud-go/issues/9632)) ([16efbb5](https://github.com/googleapis/google-cloud-go/commit/16efbb52e39ea4a319e5ee1e95c0e0305b6d9824))
|
||||||
|
* **auth:** Remove content-type header from idms get requests ([#9508](https://github.com/googleapis/google-cloud-go/issues/9508)) ([8589f41](https://github.com/googleapis/google-cloud-go/commit/8589f41599d265d7c3d46a3d86c9fab2329cbdd9))
|
||||||
|
* **auth:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
||||||
|
|
||||||
|
## [0.1.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.1.0...auth/v0.1.1) (2024-03-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/impersonate:** Properly send default detect params ([#9529](https://github.com/googleapis/google-cloud-go/issues/9529)) ([5b6b8be](https://github.com/googleapis/google-cloud-go/commit/5b6b8bef577f82707e51f5cc5d258d5bdf90218f)), refs [#9136](https://github.com/googleapis/google-cloud-go/issues/9136)
|
||||||
|
* **auth:** Update grpc-go to v1.56.3 ([343cea8](https://github.com/googleapis/google-cloud-go/commit/343cea8c43b1e31ae21ad50ad31d3b0b60143f8c))
|
||||||
|
* **auth:** Update grpc-go to v1.59.0 ([81a97b0](https://github.com/googleapis/google-cloud-go/commit/81a97b06cb28b25432e4ece595c55a9857e960b7))
|
||||||
|
|
||||||
|
## 0.1.0 (2023-10-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** Add base auth package ([#8465](https://github.com/googleapis/google-cloud-go/issues/8465)) ([6a45f26](https://github.com/googleapis/google-cloud-go/commit/6a45f26b809b64edae21f312c18d4205f96b180e))
|
||||||
|
* **auth:** Add cert support to httptransport ([#8569](https://github.com/googleapis/google-cloud-go/issues/8569)) ([37e3435](https://github.com/googleapis/google-cloud-go/commit/37e3435f8e98595eafab481bdfcb31a4c56fa993))
|
||||||
|
* **auth:** Add Credentials.UniverseDomain() ([#8654](https://github.com/googleapis/google-cloud-go/issues/8654)) ([af0aa1e](https://github.com/googleapis/google-cloud-go/commit/af0aa1ed8015bc8fe0dd87a7549ae029107cbdb8))
|
||||||
|
* **auth:** Add detect package ([#8491](https://github.com/googleapis/google-cloud-go/issues/8491)) ([d977419](https://github.com/googleapis/google-cloud-go/commit/d977419a3269f6acc193df77a2136a6eb4b4add7))
|
||||||
|
* **auth:** Add downscope package ([#8532](https://github.com/googleapis/google-cloud-go/issues/8532)) ([dda9bff](https://github.com/googleapis/google-cloud-go/commit/dda9bff8ec70e6d104901b4105d13dcaa4e2404c))
|
||||||
|
* **auth:** Add grpctransport package ([#8625](https://github.com/googleapis/google-cloud-go/issues/8625)) ([69a8347](https://github.com/googleapis/google-cloud-go/commit/69a83470bdcc7ed10c6c36d1abc3b7cfdb8a0ee5))
|
||||||
|
* **auth:** Add httptransport package ([#8567](https://github.com/googleapis/google-cloud-go/issues/8567)) ([6898597](https://github.com/googleapis/google-cloud-go/commit/6898597d2ea95d630fcd00fd15c58c75ea843bff))
|
||||||
|
* **auth:** Add idtoken package ([#8580](https://github.com/googleapis/google-cloud-go/issues/8580)) ([a79e693](https://github.com/googleapis/google-cloud-go/commit/a79e693e97e4e3e1c6742099af3dbc58866d88fe))
|
||||||
|
* **auth:** Add impersonate package ([#8578](https://github.com/googleapis/google-cloud-go/issues/8578)) ([e29ba0c](https://github.com/googleapis/google-cloud-go/commit/e29ba0cb7bd3888ab9e808087027dc5a32474c04))
|
||||||
|
* **auth:** Add support for external accounts in detect ([#8508](https://github.com/googleapis/google-cloud-go/issues/8508)) ([62210d5](https://github.com/googleapis/google-cloud-go/commit/62210d5d3e56e8e9f35db8e6ac0defec19582507))
|
||||||
|
* **auth:** Port external account changes ([#8697](https://github.com/googleapis/google-cloud-go/issues/8697)) ([5823db5](https://github.com/googleapis/google-cloud-go/commit/5823db5d633069999b58b9131a7f9cd77e82c899))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
||||||
|
* **auth:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
||||||
202
vendor/cloud.google.com/go/auth/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/auth/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.
|
||||||
40
vendor/cloud.google.com/go/auth/README.md
generated
vendored
Normal file
40
vendor/cloud.google.com/go/auth/README.md
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Google Auth Library for Go
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/cloud.google.com/go/auth)
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
go get cloud.google.com/go/auth@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The most common way this library is used is transitively, by default, from any
|
||||||
|
of our Go client libraries.
|
||||||
|
|
||||||
|
### Notable use-cases
|
||||||
|
|
||||||
|
- To create a credential directly please see examples in the
|
||||||
|
[credentials](https://pkg.go.dev/cloud.google.com/go/auth/credentials)
|
||||||
|
package.
|
||||||
|
- To create a authenticated HTTP client please see examples in the
|
||||||
|
[httptransport](https://pkg.go.dev/cloud.google.com/go/auth/httptransport)
|
||||||
|
package.
|
||||||
|
- To create a authenticated gRPC connection please see examples in the
|
||||||
|
[grpctransport](https://pkg.go.dev/cloud.google.com/go/auth/grpctransport)
|
||||||
|
package.
|
||||||
|
- To create an ID token please see examples in the
|
||||||
|
[idtoken](https://pkg.go.dev/cloud.google.com/go/auth/credentials/idtoken)
|
||||||
|
package.
|
||||||
|
|
||||||
|
## 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.
|
||||||
618
vendor/cloud.google.com/go/auth/auth.go
generated
vendored
Normal file
618
vendor/cloud.google.com/go/auth/auth.go
generated
vendored
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
// Copyright 2023 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 auth provides utilities for managing Google Cloud credentials,
|
||||||
|
// including functionality for creating, caching, and refreshing OAuth2 tokens.
|
||||||
|
// It offers customizable options for different OAuth2 flows, such as 2-legged
|
||||||
|
// (2LO) and 3-legged (3LO) OAuth, along with support for PKCE and automatic
|
||||||
|
// token management.
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/jwt"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Parameter keys for AuthCodeURL method to support PKCE.
|
||||||
|
codeChallengeKey = "code_challenge"
|
||||||
|
codeChallengeMethodKey = "code_challenge_method"
|
||||||
|
|
||||||
|
// Parameter key for Exchange method to support PKCE.
|
||||||
|
codeVerifierKey = "code_verifier"
|
||||||
|
|
||||||
|
// 3 minutes and 45 seconds before expiration. The shortest MDS cache is 4 minutes,
|
||||||
|
// so we give it 15 seconds to refresh it's cache before attempting to refresh a token.
|
||||||
|
defaultExpiryDelta = 225 * time.Second
|
||||||
|
|
||||||
|
universeDomainDefault = "googleapis.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tokenState represents different states for a [Token].
|
||||||
|
type tokenState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// fresh indicates that the [Token] is valid. It is not expired or close to
|
||||||
|
// expired, or the token has no expiry.
|
||||||
|
fresh tokenState = iota
|
||||||
|
// stale indicates that the [Token] is close to expired, and should be
|
||||||
|
// refreshed. The token can be used normally.
|
||||||
|
stale
|
||||||
|
// invalid indicates that the [Token] is expired or invalid. The token
|
||||||
|
// cannot be used for a normal operation.
|
||||||
|
invalid
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
||||||
|
defaultHeader = &jwt.Header{Algorithm: jwt.HeaderAlgRSA256, Type: jwt.HeaderType}
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
timeNow = time.Now
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenProvider specifies an interface for anything that can return a token.
|
||||||
|
type TokenProvider interface {
|
||||||
|
// Token returns a Token or an error.
|
||||||
|
// The Token returned must be safe to use
|
||||||
|
// concurrently.
|
||||||
|
// The returned Token must not be modified.
|
||||||
|
// The context provided must be sent along to any requests that are made in
|
||||||
|
// the implementing code.
|
||||||
|
Token(context.Context) (*Token, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token holds the credential token used to authorized requests. All fields are
|
||||||
|
// considered read-only.
|
||||||
|
type Token struct {
|
||||||
|
// Value is the token used to authorize requests. It is usually an access
|
||||||
|
// token but may be other types of tokens such as ID tokens in some flows.
|
||||||
|
Value string
|
||||||
|
// Type is the type of token Value is. If uninitialized, it should be
|
||||||
|
// assumed to be a "Bearer" token.
|
||||||
|
Type string
|
||||||
|
// Expiry is the time the token is set to expire.
|
||||||
|
Expiry time.Time
|
||||||
|
// Metadata may include, but is not limited to, the body of the token
|
||||||
|
// response returned by the server.
|
||||||
|
Metadata map[string]interface{} // TODO(codyoss): maybe make a method to flatten metadata to avoid []string for url.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports that a [Token] is non-nil, has a [Token.Value], and has not
|
||||||
|
// expired. A token is considered expired if [Token.Expiry] has passed or will
|
||||||
|
// pass in the next 225 seconds.
|
||||||
|
func (t *Token) IsValid() bool {
|
||||||
|
return t.isValidWithEarlyExpiry(defaultExpiryDelta)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadataString is a convenience method for accessing string values in the
|
||||||
|
// token's metadata. Returns an empty string if the metadata is nil or the value
|
||||||
|
// for the given key cannot be cast to a string.
|
||||||
|
func (t *Token) MetadataString(k string) string {
|
||||||
|
if t.Metadata == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s, ok := t.Metadata[k].(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) isValidWithEarlyExpiry(earlyExpiry time.Duration) bool {
|
||||||
|
if t.isEmpty() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if t.Expiry.IsZero() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return !t.Expiry.Round(0).Add(-earlyExpiry).Before(timeNow())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) isEmpty() bool {
|
||||||
|
return t == nil || t.Value == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credentials holds Google credentials, including
|
||||||
|
// [Application Default Credentials].
|
||||||
|
//
|
||||||
|
// [Application Default Credentials]: https://developers.google.com/accounts/docs/application-default-credentials
|
||||||
|
type Credentials struct {
|
||||||
|
json []byte
|
||||||
|
projectID CredentialsPropertyProvider
|
||||||
|
quotaProjectID CredentialsPropertyProvider
|
||||||
|
// universeDomain is the default service domain for a given Cloud universe.
|
||||||
|
universeDomain CredentialsPropertyProvider
|
||||||
|
|
||||||
|
TokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON returns the bytes associated with the the file used to source
|
||||||
|
// credentials if one was used.
|
||||||
|
func (c *Credentials) JSON() []byte {
|
||||||
|
return c.json
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID returns the associated project ID from the underlying file or
|
||||||
|
// environment.
|
||||||
|
func (c *Credentials) ProjectID(ctx context.Context) (string, error) {
|
||||||
|
if c.projectID == nil {
|
||||||
|
return internal.GetProjectID(c.json, ""), nil
|
||||||
|
}
|
||||||
|
v, err := c.projectID.GetProperty(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return internal.GetProjectID(c.json, v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QuotaProjectID returns the associated quota project ID from the underlying
|
||||||
|
// file or environment.
|
||||||
|
func (c *Credentials) QuotaProjectID(ctx context.Context) (string, error) {
|
||||||
|
if c.quotaProjectID == nil {
|
||||||
|
return internal.GetQuotaProject(c.json, ""), nil
|
||||||
|
}
|
||||||
|
v, err := c.quotaProjectID.GetProperty(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return internal.GetQuotaProject(c.json, v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UniverseDomain returns the default service domain for a given Cloud universe.
|
||||||
|
// The default value is "googleapis.com".
|
||||||
|
func (c *Credentials) UniverseDomain(ctx context.Context) (string, error) {
|
||||||
|
if c.universeDomain == nil {
|
||||||
|
return universeDomainDefault, nil
|
||||||
|
}
|
||||||
|
v, err := c.universeDomain.GetProperty(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
return universeDomainDefault, nil
|
||||||
|
}
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialsPropertyProvider provides an implementation to fetch a property
|
||||||
|
// value for [Credentials].
|
||||||
|
type CredentialsPropertyProvider interface {
|
||||||
|
GetProperty(context.Context) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialsPropertyFunc is a type adapter to allow the use of ordinary
|
||||||
|
// functions as a [CredentialsPropertyProvider].
|
||||||
|
type CredentialsPropertyFunc func(context.Context) (string, error)
|
||||||
|
|
||||||
|
// GetProperty loads the properly value provided the given context.
|
||||||
|
func (p CredentialsPropertyFunc) GetProperty(ctx context.Context) (string, error) {
|
||||||
|
return p(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialsOptions are used to configure [Credentials].
|
||||||
|
type CredentialsOptions struct {
|
||||||
|
// TokenProvider is a means of sourcing a token for the credentials. Required.
|
||||||
|
TokenProvider TokenProvider
|
||||||
|
// JSON is the raw contents of the credentials file if sourced from a file.
|
||||||
|
JSON []byte
|
||||||
|
// ProjectIDProvider resolves the project ID associated with the
|
||||||
|
// credentials.
|
||||||
|
ProjectIDProvider CredentialsPropertyProvider
|
||||||
|
// QuotaProjectIDProvider resolves the quota project ID associated with the
|
||||||
|
// credentials.
|
||||||
|
QuotaProjectIDProvider CredentialsPropertyProvider
|
||||||
|
// UniverseDomainProvider resolves the universe domain with the credentials.
|
||||||
|
UniverseDomainProvider CredentialsPropertyProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns new [Credentials] from the provided options.
|
||||||
|
func NewCredentials(opts *CredentialsOptions) *Credentials {
|
||||||
|
creds := &Credentials{
|
||||||
|
TokenProvider: opts.TokenProvider,
|
||||||
|
json: opts.JSON,
|
||||||
|
projectID: opts.ProjectIDProvider,
|
||||||
|
quotaProjectID: opts.QuotaProjectIDProvider,
|
||||||
|
universeDomain: opts.UniverseDomainProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds
|
||||||
|
}
|
||||||
|
|
||||||
|
// CachedTokenProviderOptions provides options for configuring a cached
|
||||||
|
// [TokenProvider].
|
||||||
|
type CachedTokenProviderOptions struct {
|
||||||
|
// DisableAutoRefresh makes the TokenProvider always return the same token,
|
||||||
|
// even if it is expired. The default is false. Optional.
|
||||||
|
DisableAutoRefresh bool
|
||||||
|
// ExpireEarly configures the amount of time before a token expires, that it
|
||||||
|
// should be refreshed. If unset, the default value is 3 minutes and 45
|
||||||
|
// seconds. Optional.
|
||||||
|
ExpireEarly time.Duration
|
||||||
|
// DisableAsyncRefresh configures a synchronous workflow that refreshes
|
||||||
|
// tokens in a blocking manner. The default is false. Optional.
|
||||||
|
DisableAsyncRefresh bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctpo *CachedTokenProviderOptions) autoRefresh() bool {
|
||||||
|
if ctpo == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return !ctpo.DisableAutoRefresh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctpo *CachedTokenProviderOptions) expireEarly() time.Duration {
|
||||||
|
if ctpo == nil || ctpo.ExpireEarly == 0 {
|
||||||
|
return defaultExpiryDelta
|
||||||
|
}
|
||||||
|
return ctpo.ExpireEarly
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctpo *CachedTokenProviderOptions) blockingRefresh() bool {
|
||||||
|
if ctpo == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ctpo.DisableAsyncRefresh
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCachedTokenProvider wraps a [TokenProvider] to cache the tokens returned
|
||||||
|
// by the underlying provider. By default it will refresh tokens asynchronously
|
||||||
|
// a few minutes before they expire.
|
||||||
|
func NewCachedTokenProvider(tp TokenProvider, opts *CachedTokenProviderOptions) TokenProvider {
|
||||||
|
if ctp, ok := tp.(*cachedTokenProvider); ok {
|
||||||
|
return ctp
|
||||||
|
}
|
||||||
|
return &cachedTokenProvider{
|
||||||
|
tp: tp,
|
||||||
|
autoRefresh: opts.autoRefresh(),
|
||||||
|
expireEarly: opts.expireEarly(),
|
||||||
|
blockingRefresh: opts.blockingRefresh(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type cachedTokenProvider struct {
|
||||||
|
tp TokenProvider
|
||||||
|
autoRefresh bool
|
||||||
|
expireEarly time.Duration
|
||||||
|
blockingRefresh bool
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
cachedToken *Token
|
||||||
|
// isRefreshRunning ensures that the non-blocking refresh will only be
|
||||||
|
// attempted once, even if multiple callers enter the Token method.
|
||||||
|
isRefreshRunning bool
|
||||||
|
// isRefreshErr ensures that the non-blocking refresh will only be attempted
|
||||||
|
// once per refresh window if an error is encountered.
|
||||||
|
isRefreshErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedTokenProvider) Token(ctx context.Context) (*Token, error) {
|
||||||
|
if c.blockingRefresh {
|
||||||
|
return c.tokenBlocking(ctx)
|
||||||
|
}
|
||||||
|
return c.tokenNonBlocking(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedTokenProvider) tokenNonBlocking(ctx context.Context) (*Token, error) {
|
||||||
|
switch c.tokenState() {
|
||||||
|
case fresh:
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.cachedToken, nil
|
||||||
|
case stale:
|
||||||
|
// Call tokenAsync with a new Context because the user-provided context
|
||||||
|
// may have a short timeout incompatible with async token refresh.
|
||||||
|
c.tokenAsync(context.Background())
|
||||||
|
// Return the stale token immediately to not block customer requests to Cloud services.
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.cachedToken, nil
|
||||||
|
default: // invalid
|
||||||
|
return c.tokenBlocking(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenState reports the token's validity.
|
||||||
|
func (c *cachedTokenProvider) tokenState() tokenState {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
t := c.cachedToken
|
||||||
|
now := timeNow()
|
||||||
|
if t == nil || t.Value == "" {
|
||||||
|
return invalid
|
||||||
|
} else if t.Expiry.IsZero() {
|
||||||
|
return fresh
|
||||||
|
} else if now.After(t.Expiry.Round(0)) {
|
||||||
|
return invalid
|
||||||
|
} else if now.After(t.Expiry.Round(0).Add(-c.expireEarly)) {
|
||||||
|
return stale
|
||||||
|
}
|
||||||
|
return fresh
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenAsync uses a bool to ensure that only one non-blocking token refresh
|
||||||
|
// happens at a time, even if multiple callers have entered this function
|
||||||
|
// concurrently. This avoids creating an arbitrary number of concurrent
|
||||||
|
// goroutines. Retries should be attempted and managed within the Token method.
|
||||||
|
// If the refresh attempt fails, no further attempts are made until the refresh
|
||||||
|
// window expires and the token enters the invalid state, at which point the
|
||||||
|
// blocking call to Token should likely return the same error on the main goroutine.
|
||||||
|
func (c *cachedTokenProvider) tokenAsync(ctx context.Context) {
|
||||||
|
fn := func() {
|
||||||
|
t, err := c.tp.Token(ctx)
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.isRefreshRunning = false
|
||||||
|
if err != nil {
|
||||||
|
// Discard errors from the non-blocking refresh, but prevent further
|
||||||
|
// attempts.
|
||||||
|
c.isRefreshErr = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.cachedToken = t
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if !c.isRefreshRunning && !c.isRefreshErr {
|
||||||
|
c.isRefreshRunning = true
|
||||||
|
go fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedTokenProvider) tokenBlocking(ctx context.Context) (*Token, error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.isRefreshErr = false
|
||||||
|
if c.cachedToken.IsValid() || (!c.autoRefresh && !c.cachedToken.isEmpty()) {
|
||||||
|
return c.cachedToken, nil
|
||||||
|
}
|
||||||
|
t, err := c.tp.Token(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.cachedToken = t
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error is a error associated with retrieving a [Token]. It can hold useful
|
||||||
|
// additional details for debugging.
|
||||||
|
type Error struct {
|
||||||
|
// Response is the HTTP response associated with error. The body will always
|
||||||
|
// be already closed and consumed.
|
||||||
|
Response *http.Response
|
||||||
|
// Body is the HTTP response body.
|
||||||
|
Body []byte
|
||||||
|
// Err is the underlying wrapped error.
|
||||||
|
Err error
|
||||||
|
|
||||||
|
// code returned in the token response
|
||||||
|
code string
|
||||||
|
// description returned in the token response
|
||||||
|
description string
|
||||||
|
// uri returned in the token response
|
||||||
|
uri string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if e.code != "" {
|
||||||
|
s := fmt.Sprintf("auth: %q", e.code)
|
||||||
|
if e.description != "" {
|
||||||
|
s += fmt.Sprintf(" %q", e.description)
|
||||||
|
}
|
||||||
|
if e.uri != "" {
|
||||||
|
s += fmt.Sprintf(" %q", e.uri)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("auth: cannot fetch token: %v\nResponse: %s", e.Response.StatusCode, e.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary returns true if the error is considered temporary and may be able
|
||||||
|
// to be retried.
|
||||||
|
func (e *Error) Temporary() bool {
|
||||||
|
if e.Response == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sc := e.Response.StatusCode
|
||||||
|
return sc == http.StatusInternalServerError || sc == http.StatusServiceUnavailable || sc == http.StatusRequestTimeout || sc == http.StatusTooManyRequests
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style describes how the token endpoint wants to receive the ClientID and
|
||||||
|
// ClientSecret.
|
||||||
|
type Style int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StyleUnknown means the value has not been initiated. Sending this in
|
||||||
|
// a request will cause the token exchange to fail.
|
||||||
|
StyleUnknown Style = iota
|
||||||
|
// StyleInParams sends client info in the body of a POST request.
|
||||||
|
StyleInParams
|
||||||
|
// StyleInHeader sends client info using Basic Authorization header.
|
||||||
|
StyleInHeader
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options2LO is the configuration settings for doing a 2-legged JWT OAuth2 flow.
|
||||||
|
type Options2LO struct {
|
||||||
|
// Email is the OAuth2 client ID. This value is set as the "iss" in the
|
||||||
|
// JWT.
|
||||||
|
Email string
|
||||||
|
// PrivateKey contains the contents of an RSA private key or the
|
||||||
|
// contents of a PEM file that contains a private key. It is used to sign
|
||||||
|
// the JWT created.
|
||||||
|
PrivateKey []byte
|
||||||
|
// TokenURL is th URL the JWT is sent to. Required.
|
||||||
|
TokenURL string
|
||||||
|
// PrivateKeyID is the ID of the key used to sign the JWT. It is used as the
|
||||||
|
// "kid" in the JWT header. Optional.
|
||||||
|
PrivateKeyID string
|
||||||
|
// Subject is the used for to impersonate a user. It is used as the "sub" in
|
||||||
|
// the JWT.m Optional.
|
||||||
|
Subject string
|
||||||
|
// Scopes specifies requested permissions for the token. Optional.
|
||||||
|
Scopes []string
|
||||||
|
// Expires specifies the lifetime of the token. Optional.
|
||||||
|
Expires time.Duration
|
||||||
|
// Audience specifies the "aud" in the JWT. Optional.
|
||||||
|
Audience string
|
||||||
|
// PrivateClaims allows specifying any custom claims for the JWT. Optional.
|
||||||
|
PrivateClaims map[string]interface{}
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
UniverseDomain string
|
||||||
|
|
||||||
|
// Client is the client to be used to make the underlying token requests.
|
||||||
|
// Optional.
|
||||||
|
Client *http.Client
|
||||||
|
// UseIDToken requests that the token returned be an ID token if one is
|
||||||
|
// returned from the server. Optional.
|
||||||
|
UseIDToken bool
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options2LO) client() *http.Client {
|
||||||
|
if o.Client != nil {
|
||||||
|
return o.Client
|
||||||
|
}
|
||||||
|
return internal.DefaultClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options2LO) validate() error {
|
||||||
|
if o == nil {
|
||||||
|
return errors.New("auth: options must be provided")
|
||||||
|
}
|
||||||
|
if o.Email == "" {
|
||||||
|
return errors.New("auth: email must be provided")
|
||||||
|
}
|
||||||
|
if len(o.PrivateKey) == 0 {
|
||||||
|
return errors.New("auth: private key must be provided")
|
||||||
|
}
|
||||||
|
if o.TokenURL == "" {
|
||||||
|
return errors.New("auth: token URL must be provided")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// New2LOTokenProvider returns a [TokenProvider] from the provided options.
|
||||||
|
func New2LOTokenProvider(opts *Options2LO) (TokenProvider, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tokenProvider2LO{opts: opts, Client: opts.client(), logger: internallog.New(opts.Logger)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenProvider2LO struct {
|
||||||
|
opts *Options2LO
|
||||||
|
Client *http.Client
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
|
||||||
|
pk, err := internal.ParseKey(tp.opts.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
claimSet := &jwt.Claims{
|
||||||
|
Iss: tp.opts.Email,
|
||||||
|
Scope: strings.Join(tp.opts.Scopes, " "),
|
||||||
|
Aud: tp.opts.TokenURL,
|
||||||
|
AdditionalClaims: tp.opts.PrivateClaims,
|
||||||
|
Sub: tp.opts.Subject,
|
||||||
|
}
|
||||||
|
if t := tp.opts.Expires; t > 0 {
|
||||||
|
claimSet.Exp = time.Now().Add(t).Unix()
|
||||||
|
}
|
||||||
|
if aud := tp.opts.Audience; aud != "" {
|
||||||
|
claimSet.Aud = aud
|
||||||
|
}
|
||||||
|
h := *defaultHeader
|
||||||
|
h.KeyID = tp.opts.PrivateKeyID
|
||||||
|
payload, err := jwt.EncodeJWS(&h, claimSet, pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("grant_type", defaultGrantType)
|
||||||
|
v.Set("assertion", payload)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", tp.opts.TokenURL, strings.NewReader(v.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
tp.logger.DebugContext(ctx, "2LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||||
|
resp, body, err := internal.DoRequest(tp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
|
||||||
|
}
|
||||||
|
tp.logger.DebugContext(ctx, "2LO token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||||
|
return nil, &Error{
|
||||||
|
Response: resp,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// tokenRes is the JSON response body.
|
||||||
|
var tokenRes struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
IDToken string `json:"id_token"`
|
||||||
|
ExpiresIn int64 `json:"expires_in"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
||||||
|
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
|
||||||
|
}
|
||||||
|
token := &Token{
|
||||||
|
Value: tokenRes.AccessToken,
|
||||||
|
Type: tokenRes.TokenType,
|
||||||
|
}
|
||||||
|
token.Metadata = make(map[string]interface{})
|
||||||
|
json.Unmarshal(body, &token.Metadata) // no error checks for optional fields
|
||||||
|
|
||||||
|
if secs := tokenRes.ExpiresIn; secs > 0 {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
|
||||||
|
}
|
||||||
|
if v := tokenRes.IDToken; v != "" {
|
||||||
|
// decode returned id token to get expiry
|
||||||
|
claimSet, err := jwt.DecodeJWS(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("auth: error decoding JWT token: %w", err)
|
||||||
|
}
|
||||||
|
token.Expiry = time.Unix(claimSet.Exp, 0)
|
||||||
|
}
|
||||||
|
if tp.opts.UseIDToken {
|
||||||
|
if tokenRes.IDToken == "" {
|
||||||
|
return nil, fmt.Errorf("auth: response doesn't have JWT token")
|
||||||
|
}
|
||||||
|
token.Value = tokenRes.IDToken
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
102
vendor/cloud.google.com/go/auth/credentials/compute.go
generated
vendored
Normal file
102
vendor/cloud.google.com/go/auth/credentials/compute.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2023 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 credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/compute/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
computeTokenMetadata = map[string]interface{}{
|
||||||
|
"auth.google.tokenSource": "compute-metadata",
|
||||||
|
"auth.google.serviceAccount": "default",
|
||||||
|
}
|
||||||
|
computeTokenURI = "instance/service-accounts/default/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// computeTokenProvider creates a [cloud.google.com/go/auth.TokenProvider] that
|
||||||
|
// uses the metadata service to retrieve tokens.
|
||||||
|
func computeTokenProvider(opts *DetectOptions, client *metadata.Client) auth.TokenProvider {
|
||||||
|
return auth.NewCachedTokenProvider(&computeProvider{
|
||||||
|
scopes: opts.Scopes,
|
||||||
|
client: client,
|
||||||
|
tokenBindingType: opts.TokenBindingType,
|
||||||
|
}, &auth.CachedTokenProviderOptions{
|
||||||
|
ExpireEarly: opts.EarlyTokenRefresh,
|
||||||
|
DisableAsyncRefresh: opts.DisableAsyncRefresh,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// computeProvider fetches tokens from the google cloud metadata service.
|
||||||
|
type computeProvider struct {
|
||||||
|
scopes []string
|
||||||
|
client *metadata.Client
|
||||||
|
tokenBindingType TokenBindingType
|
||||||
|
}
|
||||||
|
|
||||||
|
type metadataTokenResp struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
ExpiresInSec int `json:"expires_in"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *computeProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
tokenURI, err := url.Parse(computeTokenURI)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hasScopes := len(cs.scopes) > 0
|
||||||
|
if hasScopes || cs.tokenBindingType != NoBinding {
|
||||||
|
v := url.Values{}
|
||||||
|
if hasScopes {
|
||||||
|
v.Set("scopes", strings.Join(cs.scopes, ","))
|
||||||
|
}
|
||||||
|
switch cs.tokenBindingType {
|
||||||
|
case MTLSHardBinding:
|
||||||
|
v.Set("transport", "mtls")
|
||||||
|
v.Set("binding-enforcement", "on")
|
||||||
|
case ALTSHardBinding:
|
||||||
|
v.Set("transport", "alts")
|
||||||
|
}
|
||||||
|
tokenURI.RawQuery = v.Encode()
|
||||||
|
}
|
||||||
|
tokenJSON, err := cs.client.GetWithContext(ctx, tokenURI.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
||||||
|
}
|
||||||
|
var res metadataTokenResp
|
||||||
|
if err := json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res); err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: invalid token JSON from metadata: %w", err)
|
||||||
|
}
|
||||||
|
if res.ExpiresInSec == 0 || res.AccessToken == "" {
|
||||||
|
return nil, errors.New("credentials: incomplete token received from metadata")
|
||||||
|
}
|
||||||
|
token := &auth.Token{
|
||||||
|
Value: res.AccessToken,
|
||||||
|
Type: res.TokenType,
|
||||||
|
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
|
||||||
|
Metadata: computeTokenMetadata,
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
471
vendor/cloud.google.com/go/auth/credentials/detect.go
generated
vendored
Normal file
471
vendor/cloud.google.com/go/auth/credentials/detect.go
generated
vendored
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
// Copyright 2023 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 credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"cloud.google.com/go/auth/internal/trustboundary"
|
||||||
|
"cloud.google.com/go/compute/metadata"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// jwtTokenURL is Google's OAuth 2.0 token URL to use with the JWT(2LO) flow.
|
||||||
|
jwtTokenURL = "https://oauth2.googleapis.com/token"
|
||||||
|
|
||||||
|
// Google's OAuth 2.0 default endpoints.
|
||||||
|
googleAuthURL = "https://accounts.google.com/o/oauth2/auth"
|
||||||
|
googleTokenURL = "https://oauth2.googleapis.com/token"
|
||||||
|
|
||||||
|
// GoogleMTLSTokenURL is Google's default OAuth2.0 mTLS endpoint.
|
||||||
|
GoogleMTLSTokenURL = "https://oauth2.mtls.googleapis.com/token"
|
||||||
|
|
||||||
|
// Help on default credentials
|
||||||
|
adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// for testing
|
||||||
|
allowOnGCECheck = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// CredType specifies the type of JSON credentials being provided
|
||||||
|
// to a loading function such as [NewCredentialsFromFile] or
|
||||||
|
// [NewCredentialsFromJSON].
|
||||||
|
type CredType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ServiceAccount represents a service account file type.
|
||||||
|
ServiceAccount CredType = "service_account"
|
||||||
|
// AuthorizedUser represents a user credentials file type.
|
||||||
|
AuthorizedUser CredType = "authorized_user"
|
||||||
|
// ExternalAccount represents an external account file type.
|
||||||
|
//
|
||||||
|
// IMPORTANT:
|
||||||
|
// This credential type does not validate the credential configuration. A security
|
||||||
|
// risk occurs when a credential configuration configured with malicious urls
|
||||||
|
// is used.
|
||||||
|
// You should validate credential configurations provided by untrusted sources.
|
||||||
|
// See [Security requirements when using credential configurations from an external
|
||||||
|
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
|
||||||
|
// for more details.
|
||||||
|
ExternalAccount CredType = "external_account"
|
||||||
|
// ImpersonatedServiceAccount represents an impersonated service account file type.
|
||||||
|
//
|
||||||
|
// IMPORTANT:
|
||||||
|
// This credential type does not validate the credential configuration. A security
|
||||||
|
// risk occurs when a credential configuration configured with malicious urls
|
||||||
|
// is used.
|
||||||
|
// You should validate credential configurations provided by untrusted sources.
|
||||||
|
// See [Security requirements when using credential configurations from an external
|
||||||
|
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
|
||||||
|
// for more details.
|
||||||
|
ImpersonatedServiceAccount CredType = "impersonated_service_account"
|
||||||
|
// GDCHServiceAccount represents a GDCH service account credentials.
|
||||||
|
GDCHServiceAccount CredType = "gdch_service_account"
|
||||||
|
// ExternalAccountAuthorizedUser represents an external account authorized user credentials.
|
||||||
|
ExternalAccountAuthorizedUser CredType = "external_account_authorized_user"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenBindingType specifies the type of binding used when requesting a token
|
||||||
|
// whether to request a hard-bound token using mTLS or an instance identity
|
||||||
|
// bound token using ALTS.
|
||||||
|
type TokenBindingType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NoBinding specifies that requested tokens are not required to have a
|
||||||
|
// binding. This is the default option.
|
||||||
|
NoBinding TokenBindingType = iota
|
||||||
|
// MTLSHardBinding specifies that a hard-bound token should be requested
|
||||||
|
// using an mTLS with S2A channel.
|
||||||
|
MTLSHardBinding
|
||||||
|
// ALTSHardBinding specifies that an instance identity bound token should
|
||||||
|
// be requested using an ALTS channel.
|
||||||
|
ALTSHardBinding
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnGCE reports whether this process is running in Google Cloud.
|
||||||
|
func OnGCE() bool {
|
||||||
|
// TODO(codyoss): once all libs use this auth lib move metadata check here
|
||||||
|
return allowOnGCECheck && metadata.OnGCE()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectDefault searches for "Application Default Credentials" and returns
|
||||||
|
// a credential based on the [DetectOptions] provided.
|
||||||
|
//
|
||||||
|
// It looks for credentials in the following places, preferring the first
|
||||||
|
// location found:
|
||||||
|
//
|
||||||
|
// - 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.
|
||||||
|
// - 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.
|
||||||
|
// - On Google Compute Engine, Google App Engine standard second generation
|
||||||
|
// runtimes, and Google App Engine flexible environment, it fetches
|
||||||
|
// credentials from the metadata server.
|
||||||
|
//
|
||||||
|
// Important: If you accept a credential configuration (credential
|
||||||
|
// JSON/File/Stream) from an external source for authentication to Google
|
||||||
|
// Cloud Platform, you must validate it before providing it to any Google
|
||||||
|
// API or library. Providing an unvalidated credential configuration to
|
||||||
|
// Google APIs can compromise the security of your systems and data. For
|
||||||
|
// more information, refer to [Validate credential configurations from
|
||||||
|
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
|
||||||
|
func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trustBoundaryEnabled, err := trustboundary.IsEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(opts.CredentialsJSON) > 0 {
|
||||||
|
return readCredentialsFileJSON(opts.CredentialsJSON, opts)
|
||||||
|
}
|
||||||
|
if opts.CredentialsFile != "" {
|
||||||
|
return readCredentialsFile(opts.CredentialsFile, opts)
|
||||||
|
}
|
||||||
|
if filename := os.Getenv(credsfile.GoogleAppCredsEnvVar); filename != "" {
|
||||||
|
creds, err := readCredentialsFile(filename, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := credsfile.GetWellKnownFileName()
|
||||||
|
if b, err := os.ReadFile(fileName); err == nil {
|
||||||
|
return readCredentialsFileJSON(b, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
if OnGCE() {
|
||||||
|
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
||||||
|
Logger: opts.logger(),
|
||||||
|
UseDefaultClient: true,
|
||||||
|
})
|
||||||
|
gceUniverseDomainProvider := &internal.ComputeUniverseDomainProvider{
|
||||||
|
MetadataClient: metadataClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := computeTokenProvider(opts, metadataClient)
|
||||||
|
if trustBoundaryEnabled {
|
||||||
|
gceConfigProvider := trustboundary.NewGCEConfigProvider(gceUniverseDomainProvider)
|
||||||
|
var err error
|
||||||
|
tp, err = trustboundary.NewProvider(opts.client(), gceConfigProvider, opts.logger(), tp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: failed to initialize GCE trust boundary provider: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return auth.NewCredentials(&auth.CredentialsOptions{
|
||||||
|
TokenProvider: tp,
|
||||||
|
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
||||||
|
return metadataClient.ProjectIDWithContext(ctx)
|
||||||
|
}),
|
||||||
|
UniverseDomainProvider: gceUniverseDomainProvider,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("credentials: could not find default credentials. See %v for more information", adcSetupURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectOptions provides configuration for [DetectDefault].
|
||||||
|
type DetectOptions struct {
|
||||||
|
// Scopes that credentials tokens should have. Example:
|
||||||
|
// https://www.googleapis.com/auth/cloud-platform. Required if Audience is
|
||||||
|
// not provided.
|
||||||
|
Scopes []string
|
||||||
|
// TokenBindingType specifies the type of binding used when requesting a
|
||||||
|
// token whether to request a hard-bound token using mTLS or an instance
|
||||||
|
// identity bound token using ALTS. Optional.
|
||||||
|
TokenBindingType TokenBindingType
|
||||||
|
// Audience that credentials tokens should have. Only applicable for 2LO
|
||||||
|
// flows with service accounts. If specified, scopes should not be provided.
|
||||||
|
Audience string
|
||||||
|
// Subject is the user email used for [domain wide delegation](https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority).
|
||||||
|
// Optional.
|
||||||
|
Subject string
|
||||||
|
// EarlyTokenRefresh configures how early before a token expires that it
|
||||||
|
// should be refreshed. Once the token’s time until expiration has entered
|
||||||
|
// this refresh window the token is considered valid but stale. If unset,
|
||||||
|
// the default value is 3 minutes and 45 seconds. Optional.
|
||||||
|
EarlyTokenRefresh time.Duration
|
||||||
|
// DisableAsyncRefresh configures a synchronous workflow that refreshes
|
||||||
|
// stale tokens while blocking. The default is false. Optional.
|
||||||
|
DisableAsyncRefresh bool
|
||||||
|
// AuthHandlerOptions configures an authorization handler and other options
|
||||||
|
// for 3LO flows. It is required, and only used, for client credential
|
||||||
|
// flows.
|
||||||
|
AuthHandlerOptions *auth.AuthorizationHandlerOptions
|
||||||
|
// TokenURL allows to set the token endpoint for user credential flows. If
|
||||||
|
// unset the default value is: https://oauth2.googleapis.com/token.
|
||||||
|
// Optional.
|
||||||
|
TokenURL string
|
||||||
|
// STSAudience is the audience sent to when retrieving an STS token.
|
||||||
|
// Currently this only used for GDCH auth flow, for which it is required.
|
||||||
|
STSAudience string
|
||||||
|
// CredentialsFile overrides detection logic and sources a credential file
|
||||||
|
// from the provided filepath. If provided, CredentialsJSON must not be.
|
||||||
|
// Optional.
|
||||||
|
//
|
||||||
|
// Deprecated: This field is deprecated because of a potential security risk.
|
||||||
|
// It does not validate the credential configuration. The security risk occurs
|
||||||
|
// when a credential configuration is accepted from a source that is not
|
||||||
|
// under your control and used without validation on your side.
|
||||||
|
//
|
||||||
|
// If you know that you will be loading credential configurations of a
|
||||||
|
// specific type, it is recommended to use a credential-type-specific
|
||||||
|
// NewCredentialsFromFile method. This will ensure that an unexpected
|
||||||
|
// credential type with potential for malicious intent is not loaded
|
||||||
|
// unintentionally. You might still have to do validation for certain
|
||||||
|
// credential types. Please follow the recommendation for that method. For
|
||||||
|
// example, if you want to load only service accounts, you can use
|
||||||
|
//
|
||||||
|
// creds, err := credentials.NewCredentialsFromFile(ctx, credentials.ServiceAccount, filename, opts)
|
||||||
|
//
|
||||||
|
// If you are loading your credential configuration from an untrusted source
|
||||||
|
// and have not mitigated the risks (e.g. by validating the configuration
|
||||||
|
// yourself), make these changes as soon as possible to prevent security
|
||||||
|
// risks to your environment.
|
||||||
|
//
|
||||||
|
// Regardless of the method used, it is always your responsibility to
|
||||||
|
// validate configurations received from external sources.
|
||||||
|
//
|
||||||
|
// For more details see:
|
||||||
|
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
|
||||||
|
CredentialsFile string
|
||||||
|
// CredentialsJSON overrides detection logic and uses the JSON bytes as the
|
||||||
|
// source for the credential. If provided, CredentialsFile must not be.
|
||||||
|
// Optional.
|
||||||
|
//
|
||||||
|
// Deprecated: This field is deprecated because of a potential security risk.
|
||||||
|
// It does not validate the credential configuration. The security risk occurs
|
||||||
|
// when a credential configuration is accepted from a source that is not
|
||||||
|
// under your control and used without validation on your side.
|
||||||
|
//
|
||||||
|
// If you know that you will be loading credential configurations of a
|
||||||
|
// specific type, it is recommended to use a credential-type-specific
|
||||||
|
// NewCredentialsFromJSON method. This will ensure that an unexpected
|
||||||
|
// credential type with potential for malicious intent is not loaded
|
||||||
|
// unintentionally. You might still have to do validation for certain
|
||||||
|
// credential types. Please follow the recommendation for that method. For
|
||||||
|
// example, if you want to load only service accounts, you can use
|
||||||
|
//
|
||||||
|
// creds, err := credentials.NewCredentialsFromJSON(ctx, credentials.ServiceAccount, json, opts)
|
||||||
|
//
|
||||||
|
// If you are loading your credential configuration from an untrusted source
|
||||||
|
// and have not mitigated the risks (e.g. by validating the configuration
|
||||||
|
// yourself), make these changes as soon as possible to prevent security
|
||||||
|
// risks to your environment.
|
||||||
|
//
|
||||||
|
// Regardless of the method used, it is always your responsibility to
|
||||||
|
// validate configurations received from external sources.
|
||||||
|
//
|
||||||
|
// For more details see:
|
||||||
|
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
|
||||||
|
CredentialsJSON []byte
|
||||||
|
// UseSelfSignedJWT directs service account based credentials to create a
|
||||||
|
// self-signed JWT with the private key found in the file, skipping any
|
||||||
|
// network requests that would normally be made. Optional.
|
||||||
|
UseSelfSignedJWT bool
|
||||||
|
// Client configures the underlying client used to make network requests
|
||||||
|
// when fetching tokens. Optional.
|
||||||
|
Client *http.Client
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
// The default value is "googleapis.com". This option is ignored for
|
||||||
|
// authentication flows that do not support universe domain. Optional.
|
||||||
|
UniverseDomain string
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsFromFile creates a [cloud.google.com/go/auth.Credentials] from
|
||||||
|
// the provided file. The credType argument specifies the expected credential
|
||||||
|
// type. If the file content does not match the expected type, an error is
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// Important: If you accept a credential configuration (credential
|
||||||
|
// JSON/File/Stream) from an external source for authentication to Google
|
||||||
|
// Cloud Platform, you must validate it before providing it to any Google
|
||||||
|
// API or library. Providing an unvalidated credential configuration to
|
||||||
|
// Google APIs can compromise the security of your systems and data. For
|
||||||
|
// more information, refer to [Validate credential configurations from
|
||||||
|
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
|
||||||
|
func NewCredentialsFromFile(credType CredType, filename string, opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
b, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewCredentialsFromJSON(credType, b, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsFromJSON creates a [cloud.google.com/go/auth.Credentials] from
|
||||||
|
// the provided JSON bytes. The credType argument specifies the expected
|
||||||
|
// credential type. If the JSON does not match the expected type, an error is
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// Important: If you accept a credential configuration (credential
|
||||||
|
// JSON/File/Stream) from an external source for authentication to Google
|
||||||
|
// Cloud Platform, you must validate it before providing it to any Google
|
||||||
|
// API or library. Providing an unvalidated credential configuration to
|
||||||
|
// Google APIs can compromise the security of your systems and data. For
|
||||||
|
// more information, refer to [Validate credential configurations from
|
||||||
|
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
|
||||||
|
func NewCredentialsFromJSON(credType CredType, b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
if err := checkCredentialType(b, credType); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// We can't use readCredentialsFileJSON because it does auto-detection
|
||||||
|
// for client_credentials.json which we don't support here (no type field).
|
||||||
|
// Instead, we call fileCredentials just as readCredentialsFileJSON does
|
||||||
|
// when it doesn't detect client_credentials.json.
|
||||||
|
return fileCredentials(b, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCredentialType(b []byte, expected CredType) error {
|
||||||
|
|
||||||
|
fileType, err := credsfile.ParseFileType(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if CredType(fileType) != expected {
|
||||||
|
return fmt.Errorf("credentials: expected type %q, found %q", expected, fileType)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DetectOptions) validate() error {
|
||||||
|
if o == nil {
|
||||||
|
return errors.New("credentials: options must be provided")
|
||||||
|
}
|
||||||
|
if len(o.Scopes) > 0 && o.Audience != "" {
|
||||||
|
return errors.New("credentials: both scopes and audience were provided")
|
||||||
|
}
|
||||||
|
if len(o.CredentialsJSON) > 0 && o.CredentialsFile != "" {
|
||||||
|
return errors.New("credentials: both credentials file and JSON were provided")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DetectOptions) tokenURL() string {
|
||||||
|
if o.TokenURL != "" {
|
||||||
|
return o.TokenURL
|
||||||
|
}
|
||||||
|
return googleTokenURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DetectOptions) scopes() []string {
|
||||||
|
scopes := make([]string, len(o.Scopes))
|
||||||
|
copy(scopes, o.Scopes)
|
||||||
|
return scopes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DetectOptions) client() *http.Client {
|
||||||
|
if o.Client != nil {
|
||||||
|
return o.Client
|
||||||
|
}
|
||||||
|
return internal.DefaultClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DetectOptions) logger() *slog.Logger {
|
||||||
|
return internallog.New(o.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCredentialsFile(filename string, opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
b, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return readCredentialsFileJSON(b, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCredentialsFileJSON(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
// attempt to parse jsonData as a Google Developers Console client_credentials.json.
|
||||||
|
config := clientCredConfigFromJSON(b, opts)
|
||||||
|
if config != nil {
|
||||||
|
if config.AuthHandlerOpts == nil {
|
||||||
|
return nil, errors.New("credentials: auth handler must be specified for this credential filetype")
|
||||||
|
}
|
||||||
|
tp, err := auth.New3LOTokenProvider(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return auth.NewCredentials(&auth.CredentialsOptions{
|
||||||
|
TokenProvider: tp,
|
||||||
|
JSON: b,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
return fileCredentials(b, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientCredConfigFromJSON(b []byte, opts *DetectOptions) *auth.Options3LO {
|
||||||
|
var creds credsfile.ClientCredentialsFile
|
||||||
|
var c *credsfile.Config3LO
|
||||||
|
if err := json.Unmarshal(b, &creds); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case creds.Web != nil:
|
||||||
|
c = creds.Web
|
||||||
|
case creds.Installed != nil:
|
||||||
|
c = creds.Installed
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(c.RedirectURIs) < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var handleOpts *auth.AuthorizationHandlerOptions
|
||||||
|
if opts.AuthHandlerOptions != nil {
|
||||||
|
handleOpts = &auth.AuthorizationHandlerOptions{
|
||||||
|
Handler: opts.AuthHandlerOptions.Handler,
|
||||||
|
State: opts.AuthHandlerOptions.State,
|
||||||
|
PKCEOpts: opts.AuthHandlerOptions.PKCEOpts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &auth.Options3LO{
|
||||||
|
ClientID: c.ClientID,
|
||||||
|
ClientSecret: c.ClientSecret,
|
||||||
|
RedirectURL: c.RedirectURIs[0],
|
||||||
|
Scopes: opts.scopes(),
|
||||||
|
AuthURL: c.AuthURI,
|
||||||
|
TokenURL: c.TokenURI,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
||||||
|
AuthHandlerOpts: handleOpts,
|
||||||
|
// TODO(codyoss): refactor this out. We need to add in auto-detection
|
||||||
|
// for this use case.
|
||||||
|
AuthStyle: auth.StyleInParams,
|
||||||
|
}
|
||||||
|
}
|
||||||
45
vendor/cloud.google.com/go/auth/credentials/doc.go
generated
vendored
Normal file
45
vendor/cloud.google.com/go/auth/credentials/doc.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2023 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 credentials 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.
|
||||||
|
//
|
||||||
|
// # Credentials
|
||||||
|
//
|
||||||
|
// The [cloud.google.com/go/auth.Credentials] type represents Google
|
||||||
|
// credentials, including Application Default Credentials.
|
||||||
|
//
|
||||||
|
// Use [DetectDefault] to obtain Application Default Credentials.
|
||||||
|
//
|
||||||
|
// Application Default Credentials 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.
|
||||||
|
//
|
||||||
|
// # Workforce Identity Federation
|
||||||
|
//
|
||||||
|
// For more information on this feature see [cloud.google.com/go/auth/credentials/externalaccount].
|
||||||
|
package credentials
|
||||||
329
vendor/cloud.google.com/go/auth/credentials/filetypes.go
generated
vendored
Normal file
329
vendor/cloud.google.com/go/auth/credentials/filetypes.go
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
// Copyright 2023 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 credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/externalaccount"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/externalaccountuser"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/gdch"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
||||||
|
internalauth "cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"cloud.google.com/go/auth/internal/trustboundary"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"
|
||||||
|
|
||||||
|
func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
|
||||||
|
fileType, err := credsfile.ParseFileType(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if fileType == "" {
|
||||||
|
return nil, errors.New("credentials: unsupported unidentified file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectID, universeDomain string
|
||||||
|
var tp auth.TokenProvider
|
||||||
|
switch CredType(fileType) {
|
||||||
|
case ServiceAccount:
|
||||||
|
f, err := credsfile.ParseServiceAccount(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleServiceAccount(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
projectID = f.ProjectID
|
||||||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
case AuthorizedUser:
|
||||||
|
f, err := credsfile.ParseUserCredentials(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleUserCredential(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
universeDomain = f.UniverseDomain
|
||||||
|
case ExternalAccount:
|
||||||
|
f, err := credsfile.ParseExternalAccount(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleExternalAccount(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
case ExternalAccountAuthorizedUser:
|
||||||
|
f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleExternalAccountAuthorizedUser(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
universeDomain = f.UniverseDomain
|
||||||
|
case ImpersonatedServiceAccount:
|
||||||
|
f, err := credsfile.ParseImpersonatedServiceAccount(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleImpersonatedServiceAccount(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
case GDCHServiceAccount:
|
||||||
|
f, err := credsfile.ParseGDCHServiceAccount(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp, err = handleGDCHServiceAccount(f, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
projectID = f.Project
|
||||||
|
universeDomain = f.UniverseDomain
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("credentials: unsupported filetype %q", fileType)
|
||||||
|
}
|
||||||
|
return auth.NewCredentials(&auth.CredentialsOptions{
|
||||||
|
TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
|
||||||
|
ExpireEarly: opts.EarlyTokenRefresh,
|
||||||
|
}),
|
||||||
|
JSON: b,
|
||||||
|
ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
|
||||||
|
// TODO(codyoss): only set quota project here if there was a user override
|
||||||
|
UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveUniverseDomain returns optsUniverseDomain if non-empty, in order to
|
||||||
|
// support configuring universe-specific credentials in code. Auth flows
|
||||||
|
// unsupported for universe domain should not use this func, but should instead
|
||||||
|
// simply set the file universe domain on the credentials.
|
||||||
|
func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string {
|
||||||
|
if optsUniverseDomain != "" {
|
||||||
|
return optsUniverseDomain
|
||||||
|
}
|
||||||
|
return fileUniverseDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
if opts.UseSelfSignedJWT {
|
||||||
|
return configureSelfSignedJWT(f, opts)
|
||||||
|
} else if ud != "" && ud != internalauth.DefaultUniverseDomain {
|
||||||
|
// For non-GDU universe domains, token exchange is impossible and services
|
||||||
|
// must support self-signed JWTs.
|
||||||
|
opts.UseSelfSignedJWT = true
|
||||||
|
return configureSelfSignedJWT(f, opts)
|
||||||
|
}
|
||||||
|
opts2LO := &auth.Options2LO{
|
||||||
|
Email: f.ClientEmail,
|
||||||
|
PrivateKey: []byte(f.PrivateKey),
|
||||||
|
PrivateKeyID: f.PrivateKeyID,
|
||||||
|
Scopes: opts.scopes(),
|
||||||
|
TokenURL: f.TokenURL,
|
||||||
|
Subject: opts.Subject,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
UniverseDomain: ud,
|
||||||
|
}
|
||||||
|
if opts2LO.TokenURL == "" {
|
||||||
|
opts2LO.TokenURL = jwtTokenURL
|
||||||
|
}
|
||||||
|
|
||||||
|
tp, err := auth.New2LOTokenProvider(opts2LO)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
trustBoundaryEnabled, err := trustboundary.IsEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !trustBoundaryEnabled {
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
saConfig := trustboundary.NewServiceAccountConfigProvider(opts2LO.Email, opts2LO.UniverseDomain)
|
||||||
|
return trustboundary.NewProvider(opts.client(), saConfig, opts.logger(), tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
opts3LO := &auth.Options3LO{
|
||||||
|
ClientID: f.ClientID,
|
||||||
|
ClientSecret: f.ClientSecret,
|
||||||
|
Scopes: opts.scopes(),
|
||||||
|
AuthURL: googleAuthURL,
|
||||||
|
TokenURL: opts.tokenURL(),
|
||||||
|
AuthStyle: auth.StyleInParams,
|
||||||
|
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
||||||
|
RefreshToken: f.RefreshToken,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
}
|
||||||
|
return auth.New3LOTokenProvider(opts3LO)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
externalOpts := &externalaccount.Options{
|
||||||
|
Audience: f.Audience,
|
||||||
|
SubjectTokenType: f.SubjectTokenType,
|
||||||
|
TokenURL: f.TokenURL,
|
||||||
|
TokenInfoURL: f.TokenInfoURL,
|
||||||
|
ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
|
||||||
|
ClientSecret: f.ClientSecret,
|
||||||
|
ClientID: f.ClientID,
|
||||||
|
CredentialSource: f.CredentialSource,
|
||||||
|
QuotaProjectID: f.QuotaProjectID,
|
||||||
|
Scopes: opts.scopes(),
|
||||||
|
WorkforcePoolUserProject: f.WorkforcePoolUserProject,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
IsDefaultClient: opts.Client == nil,
|
||||||
|
}
|
||||||
|
if f.ServiceAccountImpersonation != nil {
|
||||||
|
externalOpts.ServiceAccountImpersonationLifetimeSeconds = f.ServiceAccountImpersonation.TokenLifetimeSeconds
|
||||||
|
}
|
||||||
|
tp, err := externalaccount.NewTokenProvider(externalOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trustBoundaryEnabled, err := trustboundary.IsEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !trustBoundaryEnabled {
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
var configProvider trustboundary.ConfigProvider
|
||||||
|
|
||||||
|
if f.ServiceAccountImpersonationURL == "" {
|
||||||
|
// No impersonation, this is a direct external account credential.
|
||||||
|
// The trust boundary is based on the workload/workforce pool.
|
||||||
|
var err error
|
||||||
|
configProvider, err = trustboundary.NewExternalAccountConfigProvider(f.Audience, ud)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Impersonation is used. The trust boundary is based on the target service account.
|
||||||
|
targetSAEmail, err := impersonate.ExtractServiceAccountEmail(f.ServiceAccountImpersonationURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: could not extract target service account email for trust boundary: %w", err)
|
||||||
|
}
|
||||||
|
configProvider = trustboundary.NewServiceAccountConfigProvider(targetSAEmail, ud)
|
||||||
|
}
|
||||||
|
|
||||||
|
return trustboundary.NewProvider(opts.client(), configProvider, opts.logger(), tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedUserFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
externalOpts := &externalaccountuser.Options{
|
||||||
|
Audience: f.Audience,
|
||||||
|
RefreshToken: f.RefreshToken,
|
||||||
|
TokenURL: f.TokenURL,
|
||||||
|
TokenInfoURL: f.TokenInfoURL,
|
||||||
|
ClientID: f.ClientID,
|
||||||
|
ClientSecret: f.ClientSecret,
|
||||||
|
Scopes: opts.scopes(),
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
}
|
||||||
|
tp, err := externalaccountuser.NewTokenProvider(externalOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trustBoundaryEnabled, err := trustboundary.IsEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !trustBoundaryEnabled {
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
configProvider, err := trustboundary.NewExternalAccountConfigProvider(f.Audience, ud)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return trustboundary.NewProvider(opts.client(), configProvider, opts.logger(), tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
if f.ServiceAccountImpersonationURL == "" || f.CredSource == nil {
|
||||||
|
return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceOpts := *opts
|
||||||
|
|
||||||
|
// Source credential needs IAM or Cloud Platform scope to call the
|
||||||
|
// iamcredentials endpoint. The scopes provided by the user are for the
|
||||||
|
// impersonated credentials.
|
||||||
|
sourceOpts.Scopes = []string{cloudPlatformScope}
|
||||||
|
sourceTP, err := fileCredentials(f.CredSource, &sourceOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||||
|
scopes := opts.scopes()
|
||||||
|
if len(scopes) == 0 {
|
||||||
|
scopes = f.Scopes
|
||||||
|
}
|
||||||
|
impOpts := &impersonate.Options{
|
||||||
|
URL: f.ServiceAccountImpersonationURL,
|
||||||
|
Scopes: scopes,
|
||||||
|
Tp: sourceTP,
|
||||||
|
Delegates: f.Delegates,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
UniverseDomain: ud,
|
||||||
|
}
|
||||||
|
tp, err := impersonate.NewTokenProvider(impOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trustBoundaryEnabled, err := trustboundary.IsEnabled()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !trustBoundaryEnabled {
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
targetSAEmail, err := impersonate.ExtractServiceAccountEmail(f.ServiceAccountImpersonationURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: could not extract target service account email for trust boundary: %w", err)
|
||||||
|
}
|
||||||
|
targetSAConfig := trustboundary.NewServiceAccountConfigProvider(targetSAEmail, ud)
|
||||||
|
return trustboundary.NewProvider(opts.client(), targetSAConfig, opts.logger(), tp)
|
||||||
|
}
|
||||||
|
func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
return gdch.NewTokenProvider(f, &gdch.Options{
|
||||||
|
STSAudience: opts.STSAudience,
|
||||||
|
Client: opts.client(),
|
||||||
|
Logger: opts.logger(),
|
||||||
|
})
|
||||||
|
}
|
||||||
531
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/aws_provider.go
generated
vendored
Normal file
531
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/aws_provider.go
generated
vendored
Normal file
@@ -0,0 +1,531 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// getenv aliases os.Getenv for testing
|
||||||
|
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 name of the header containing the session token for metadata endpoint calls
|
||||||
|
awsIMDSv2SessionTokenHeader = "X-aws-ec2-metadata-token"
|
||||||
|
|
||||||
|
awsIMDSv2SessionTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds"
|
||||||
|
|
||||||
|
awsIMDSv2SessionTTL = "300"
|
||||||
|
|
||||||
|
// The AWS authorization header name for the auto-generated date.
|
||||||
|
awsDateHeader = "x-amz-date"
|
||||||
|
|
||||||
|
defaultRegionalCredentialVerificationURL = "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
|
||||||
|
|
||||||
|
// Supported AWS configuration environment variables.
|
||||||
|
awsAccessKeyIDEnvVar = "AWS_ACCESS_KEY_ID"
|
||||||
|
awsDefaultRegionEnvVar = "AWS_DEFAULT_REGION"
|
||||||
|
awsRegionEnvVar = "AWS_REGION"
|
||||||
|
awsSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY"
|
||||||
|
awsSessionTokenEnvVar = "AWS_SESSION_TOKEN"
|
||||||
|
|
||||||
|
awsTimeFormatLong = "20060102T150405Z"
|
||||||
|
awsTimeFormatShort = "20060102"
|
||||||
|
awsProviderType = "aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
type awsSubjectProvider struct {
|
||||||
|
EnvironmentID string
|
||||||
|
RegionURL string
|
||||||
|
RegionalCredVerificationURL string
|
||||||
|
CredVerificationURL string
|
||||||
|
IMDSv2SessionTokenURL string
|
||||||
|
TargetResource string
|
||||||
|
requestSigner *awsRequestSigner
|
||||||
|
region string
|
||||||
|
securityCredentialsProvider AwsSecurityCredentialsProvider
|
||||||
|
reqOpts *RequestOptions
|
||||||
|
|
||||||
|
Client *http.Client
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
||||||
|
// Set Defaults
|
||||||
|
if sp.RegionalCredVerificationURL == "" {
|
||||||
|
sp.RegionalCredVerificationURL = defaultRegionalCredentialVerificationURL
|
||||||
|
}
|
||||||
|
headers := make(map[string]string)
|
||||||
|
if sp.shouldUseMetadataServer() {
|
||||||
|
awsSessionToken, err := sp.getAWSSessionToken(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if awsSessionToken != "" {
|
||||||
|
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sp.requestSigner = &awsRequestSigner{
|
||||||
|
RegionName: sp.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.NewRequestWithContext(ctx, "POST", strings.Replace(sp.RegionalCredVerificationURL, "{region}", sp.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 sp.TargetResource != "" {
|
||||||
|
req.Header.Set("x-goog-cloud-target-resource", sp.TargetResource)
|
||||||
|
}
|
||||||
|
sp.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 (sp *awsSubjectProvider) providerType() string {
|
||||||
|
if sp.securityCredentialsProvider != nil {
|
||||||
|
return programmaticProviderType
|
||||||
|
}
|
||||||
|
return awsProviderType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) getAWSSessionToken(ctx context.Context) (string, error) {
|
||||||
|
if sp.IMDSv2SessionTokenURL == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "PUT", sp.IMDSv2SessionTokenURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set(awsIMDSv2SessionTTLHeader, awsIMDSv2SessionTTL)
|
||||||
|
|
||||||
|
sp.logger.DebugContext(ctx, "aws session token request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws session token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("credentials: unable to retrieve AWS session token: %s", body)
|
||||||
|
}
|
||||||
|
return string(body), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) getRegion(ctx context.Context, headers map[string]string) (string, error) {
|
||||||
|
if sp.securityCredentialsProvider != nil {
|
||||||
|
return sp.securityCredentialsProvider.AwsRegion(ctx, sp.reqOpts)
|
||||||
|
}
|
||||||
|
if canRetrieveRegionFromEnvironment() {
|
||||||
|
if envAwsRegion := getenv(awsRegionEnvVar); envAwsRegion != "" {
|
||||||
|
return envAwsRegion, nil
|
||||||
|
}
|
||||||
|
return getenv(awsDefaultRegionEnvVar), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp.RegionURL == "" {
|
||||||
|
return "", errors.New("credentials: unable to determine AWS region")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", sp.RegionURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, value := range headers {
|
||||||
|
req.Header.Add(name, value)
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws region request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws region response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("credentials: unable to retrieve AWS region - %s", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This endpoint will return the region in format: us-east-2b.
|
||||||
|
// Only the us-east-2 part should be used.
|
||||||
|
bodyLen := len(body)
|
||||||
|
if bodyLen == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return string(body[:bodyLen-1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) getSecurityCredentials(ctx context.Context, headers map[string]string) (result *AwsSecurityCredentials, err error) {
|
||||||
|
if sp.securityCredentialsProvider != nil {
|
||||||
|
return sp.securityCredentialsProvider.AwsSecurityCredentials(ctx, sp.reqOpts)
|
||||||
|
}
|
||||||
|
if canRetrieveSecurityCredentialFromEnvironment() {
|
||||||
|
return &AwsSecurityCredentials{
|
||||||
|
AccessKeyID: getenv(awsAccessKeyIDEnvVar),
|
||||||
|
SecretAccessKey: getenv(awsSecretAccessKeyEnvVar),
|
||||||
|
SessionToken: getenv(awsSessionTokenEnvVar),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
roleName, err := sp.getMetadataRoleName(ctx, headers)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
credentials, err := sp.getMetadataSecurityCredentials(ctx, roleName, headers)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if credentials.AccessKeyID == "" {
|
||||||
|
return result, errors.New("credentials: missing AccessKeyId credential")
|
||||||
|
}
|
||||||
|
if credentials.SecretAccessKey == "" {
|
||||||
|
return result, errors.New("credentials: missing SecretAccessKey credential")
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) getMetadataSecurityCredentials(ctx context.Context, roleName string, headers map[string]string) (*AwsSecurityCredentials, error) {
|
||||||
|
var result *AwsSecurityCredentials
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s", sp.CredVerificationURL, roleName), nil)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
for name, value := range headers {
|
||||||
|
req.Header.Add(name, value)
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws security credential request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws security credential response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return result, fmt.Errorf("credentials: unable to retrieve AWS security credentials - %s", body)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) getMetadataRoleName(ctx context.Context, headers map[string]string) (string, error) {
|
||||||
|
if sp.CredVerificationURL == "" {
|
||||||
|
return "", errors.New("credentials: unable to determine the AWS metadata server security credentials endpoint")
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", sp.CredVerificationURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for name, value := range headers {
|
||||||
|
req.Header.Add(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.logger.DebugContext(ctx, "aws metadata role request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sp.logger.DebugContext(ctx, "aws metadata role response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("credentials: unable to retrieve AWS role name - %s", body)
|
||||||
|
}
|
||||||
|
return string(body), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature.
|
||||||
|
type awsRequestSigner struct {
|
||||||
|
RegionName string
|
||||||
|
AwsSecurityCredentials *AwsSecurityCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// req is assumed non-nil
|
||||||
|
signedRequest := cloneRequest(req)
|
||||||
|
timestamp := Now()
|
||||||
|
signedRequest.Header.Set("host", requestHost(req))
|
||||||
|
if rs.AwsSecurityCredentials.SessionToken != "" {
|
||||||
|
signedRequest.Header.Set(awsSecurityTokenHeader, rs.AwsSecurityCredentials.SessionToken)
|
||||||
|
}
|
||||||
|
if signedRequest.Header.Get("date") == "" {
|
||||||
|
signedRequest.Header.Set(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 := strings.Join([]string{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 := strings.Join([]string{awsAlgorithm, timestamp.Format(awsTimeFormatLong), credentialScope, requestHash}, "\n")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = internal.ReadAll(requestBody)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. Only one is
|
||||||
|
// required.
|
||||||
|
func canRetrieveRegionFromEnvironment() bool {
|
||||||
|
return getenv(awsRegionEnvVar) != "" || getenv(awsDefaultRegionEnvVar) != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available.
|
||||||
|
func canRetrieveSecurityCredentialFromEnvironment() bool {
|
||||||
|
return getenv(awsAccessKeyIDEnvVar) != "" && getenv(awsSecretAccessKeyEnvVar) != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *awsSubjectProvider) shouldUseMetadataServer() bool {
|
||||||
|
return sp.securityCredentialsProvider == nil && (!canRetrieveRegionFromEnvironment() || !canRetrieveSecurityCredentialFromEnvironment())
|
||||||
|
}
|
||||||
284
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/executable_provider.go
generated
vendored
Normal file
284
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/executable_provider.go
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
executableSupportedMaxVersion = 1
|
||||||
|
executableDefaultTimeout = 30 * time.Second
|
||||||
|
executableSource = "response"
|
||||||
|
executableProviderType = "executable"
|
||||||
|
outputFileSource = "output file"
|
||||||
|
|
||||||
|
allowExecutablesEnvVar = "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
|
||||||
|
|
||||||
|
jwtTokenType = "urn:ietf:params:oauth:token-type:jwt"
|
||||||
|
idTokenType = "urn:ietf:params:oauth:token-type:id_token"
|
||||||
|
saml2TokenType = "urn:ietf:params:oauth:token-type:saml2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
serviceAccountImpersonationRE = regexp.MustCompile(`https://iamcredentials..+/v1/projects/-/serviceAccounts/(.*@.*):generateAccessToken`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type nonCacheableError struct {
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nce nonCacheableError) Error() string {
|
||||||
|
return nce.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// environment is a contract for testing
|
||||||
|
type environment interface {
|
||||||
|
existingEnv() []string
|
||||||
|
getenv(string) string
|
||||||
|
run(ctx context.Context, command string, env []string) ([]byte, error)
|
||||||
|
now() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type runtimeEnvironment struct{}
|
||||||
|
|
||||||
|
func (r runtimeEnvironment) existingEnv() []string {
|
||||||
|
return os.Environ()
|
||||||
|
}
|
||||||
|
func (r runtimeEnvironment) getenv(key string) string {
|
||||||
|
return os.Getenv(key)
|
||||||
|
}
|
||||||
|
func (r runtimeEnvironment) now() time.Time {
|
||||||
|
return time.Now().UTC()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r runtimeEnvironment) run(ctx context.Context, command string, env []string) ([]byte, error) {
|
||||||
|
splitCommand := strings.Fields(command)
|
||||||
|
cmd := exec.CommandContext(ctx, splitCommand[0], splitCommand[1:]...)
|
||||||
|
cmd.Env = env
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return nil, context.DeadlineExceeded
|
||||||
|
}
|
||||||
|
if exitError, ok := err.(*exec.ExitError); ok {
|
||||||
|
return nil, exitCodeError(exitError)
|
||||||
|
}
|
||||||
|
return nil, executableError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesStdout := bytes.TrimSpace(stdout.Bytes())
|
||||||
|
if len(bytesStdout) > 0 {
|
||||||
|
return bytesStdout, nil
|
||||||
|
}
|
||||||
|
return bytes.TrimSpace(stderr.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type executableSubjectProvider struct {
|
||||||
|
Command string
|
||||||
|
Timeout time.Duration
|
||||||
|
OutputFile string
|
||||||
|
client *http.Client
|
||||||
|
opts *Options
|
||||||
|
env environment
|
||||||
|
}
|
||||||
|
|
||||||
|
type executableResponse struct {
|
||||||
|
Version int `json:"version,omitempty"`
|
||||||
|
Success *bool `json:"success,omitempty"`
|
||||||
|
TokenType string `json:"token_type,omitempty"`
|
||||||
|
ExpirationTime int64 `json:"expiration_time,omitempty"`
|
||||||
|
IDToken string `json:"id_token,omitempty"`
|
||||||
|
SamlResponse string `json:"saml_response,omitempty"`
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) parseSubjectTokenFromSource(response []byte, source string, now int64) (string, error) {
|
||||||
|
var result executableResponse
|
||||||
|
if err := json.Unmarshal(response, &result); err != nil {
|
||||||
|
return "", jsonParsingError(source, string(response))
|
||||||
|
}
|
||||||
|
// Validate
|
||||||
|
if result.Version == 0 {
|
||||||
|
return "", missingFieldError(source, "version")
|
||||||
|
}
|
||||||
|
if result.Success == nil {
|
||||||
|
return "", missingFieldError(source, "success")
|
||||||
|
}
|
||||||
|
if !*result.Success {
|
||||||
|
if result.Code == "" || result.Message == "" {
|
||||||
|
return "", malformedFailureError()
|
||||||
|
}
|
||||||
|
return "", userDefinedError(result.Code, result.Message)
|
||||||
|
}
|
||||||
|
if result.Version > executableSupportedMaxVersion || result.Version < 0 {
|
||||||
|
return "", unsupportedVersionError(source, result.Version)
|
||||||
|
}
|
||||||
|
if result.ExpirationTime == 0 && sp.OutputFile != "" {
|
||||||
|
return "", missingFieldError(source, "expiration_time")
|
||||||
|
}
|
||||||
|
if result.TokenType == "" {
|
||||||
|
return "", missingFieldError(source, "token_type")
|
||||||
|
}
|
||||||
|
if result.ExpirationTime != 0 && result.ExpirationTime < now {
|
||||||
|
return "", tokenExpiredError()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch result.TokenType {
|
||||||
|
case jwtTokenType, idTokenType:
|
||||||
|
if result.IDToken == "" {
|
||||||
|
return "", missingFieldError(source, "id_token")
|
||||||
|
}
|
||||||
|
return result.IDToken, nil
|
||||||
|
case saml2TokenType:
|
||||||
|
if result.SamlResponse == "" {
|
||||||
|
return "", missingFieldError(source, "saml_response")
|
||||||
|
}
|
||||||
|
return result.SamlResponse, nil
|
||||||
|
default:
|
||||||
|
return "", tokenTypeError(source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
||||||
|
if token, err := sp.getTokenFromOutputFile(); token != "" || err != nil {
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
return sp.getTokenFromExecutableCommand(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) providerType() string {
|
||||||
|
return executableProviderType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) getTokenFromOutputFile() (token string, err error) {
|
||||||
|
if sp.OutputFile == "" {
|
||||||
|
// This ExecutableCredentialSource doesn't use an OutputFile.
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(sp.OutputFile)
|
||||||
|
if err != nil {
|
||||||
|
// No OutputFile found. Hasn't been created yet, so skip it.
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
data, err := internal.ReadAll(file)
|
||||||
|
if err != nil || len(data) == 0 {
|
||||||
|
// Cachefile exists, but no data found. Get new credential.
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err = sp.parseSubjectTokenFromSource(data, outputFileSource, sp.env.now().Unix())
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(nonCacheableError); ok {
|
||||||
|
// If the cached token is expired we need a new token,
|
||||||
|
// and if the cache contains a failure, we need to try again.
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// There was an error in the cached token, and the developer should be aware of it.
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// Token parsing succeeded. Use found token.
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) executableEnvironment() []string {
|
||||||
|
result := sp.env.existingEnv()
|
||||||
|
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", sp.opts.Audience))
|
||||||
|
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", sp.opts.SubjectTokenType))
|
||||||
|
result = append(result, "GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0")
|
||||||
|
if sp.opts.ServiceAccountImpersonationURL != "" {
|
||||||
|
matches := serviceAccountImpersonationRE.FindStringSubmatch(sp.opts.ServiceAccountImpersonationURL)
|
||||||
|
if matches != nil {
|
||||||
|
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL=%v", matches[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sp.OutputFile != "" {
|
||||||
|
result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", sp.OutputFile))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *executableSubjectProvider) getTokenFromExecutableCommand(ctx context.Context) (string, error) {
|
||||||
|
// For security reasons, we need our consumers to set this environment variable to allow executables to be run.
|
||||||
|
if sp.env.getenv(allowExecutablesEnvVar) != "1" {
|
||||||
|
return "", errors.New("credentials: executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithDeadline(ctx, sp.env.now().Add(sp.Timeout))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
output, err := sp.env.run(ctx, sp.Command, sp.executableEnvironment())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return sp.parseSubjectTokenFromSource(output, executableSource, sp.env.now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func missingFieldError(source, field string) error {
|
||||||
|
return fmt.Errorf("credentials: %q missing %q field", source, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonParsingError(source, data string) error {
|
||||||
|
return fmt.Errorf("credentials: unable to parse %q: %v", source, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func malformedFailureError() error {
|
||||||
|
return nonCacheableError{"credentials: response must include `error` and `message` fields when unsuccessful"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userDefinedError(code, message string) error {
|
||||||
|
return nonCacheableError{fmt.Sprintf("credentials: response contains unsuccessful response: (%v) %v", code, message)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsupportedVersionError(source string, version int) error {
|
||||||
|
return fmt.Errorf("credentials: %v contains unsupported version: %v", source, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenExpiredError() error {
|
||||||
|
return nonCacheableError{"credentials: the token returned by the executable is expired"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenTypeError(source string) error {
|
||||||
|
return fmt.Errorf("credentials: %v contains unsupported token type", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exitCodeError(err *exec.ExitError) error {
|
||||||
|
return fmt.Errorf("credentials: executable command failed with exit code %v: %w", err.ExitCode(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func executableError(err error) error {
|
||||||
|
return fmt.Errorf("credentials: executable command failed: %w", err)
|
||||||
|
}
|
||||||
431
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/externalaccount.go
generated
vendored
Normal file
431
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/externalaccount.go
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
timeoutMinimum = 5 * time.Second
|
||||||
|
timeoutMaximum = 120 * time.Second
|
||||||
|
|
||||||
|
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
||||||
|
defaultTokenURL = "https://sts.UNIVERSE_DOMAIN/v1/token"
|
||||||
|
defaultUniverseDomain = "googleapis.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Now aliases time.Now for testing
|
||||||
|
Now = func() time.Time {
|
||||||
|
return time.Now().UTC()
|
||||||
|
}
|
||||||
|
validWorkforceAudiencePattern *regexp.Regexp = regexp.MustCompile(`//iam\.googleapis\.com/locations/[^/]+/workforcePools/`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options stores the configuration for fetching tokens with external credentials.
|
||||||
|
type Options 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
|
||||||
|
// ServiceAccountImpersonationLifetimeSeconds is the number of seconds the service account impersonation
|
||||||
|
// token will be valid for.
|
||||||
|
ServiceAccountImpersonationLifetimeSeconds int
|
||||||
|
// 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 *credsfile.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
|
||||||
|
// WorkforcePoolUserProject should be set when it is a workforce pool and
|
||||||
|
// not a workload identity pool. The underlying principal must still have
|
||||||
|
// serviceusage.services.use IAM permission to use the project for
|
||||||
|
// billing/quota. Optional.
|
||||||
|
WorkforcePoolUserProject string
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
// This value will be used in the default STS token URL. The default value
|
||||||
|
// is "googleapis.com". It will not be used if TokenURL is set. Optional.
|
||||||
|
UniverseDomain string
|
||||||
|
// SubjectTokenProvider is an optional token provider for OIDC/SAML
|
||||||
|
// credentials. One of SubjectTokenProvider, AWSSecurityCredentialProvider
|
||||||
|
// or CredentialSource must be provided. Optional.
|
||||||
|
SubjectTokenProvider SubjectTokenProvider
|
||||||
|
// AwsSecurityCredentialsProvider is an AWS Security Credential provider
|
||||||
|
// for AWS credentials. One of SubjectTokenProvider,
|
||||||
|
// AWSSecurityCredentialProvider or CredentialSource must be provided. Optional.
|
||||||
|
AwsSecurityCredentialsProvider AwsSecurityCredentialsProvider
|
||||||
|
// Client for token request.
|
||||||
|
Client *http.Client
|
||||||
|
// IsDefaultClient marks whether the client passed in is a default client that can be overriden.
|
||||||
|
// This is important for X509 credentials which should create a new client if the default was used
|
||||||
|
// but should respect a client explicitly passed in by the user.
|
||||||
|
IsDefaultClient bool
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubjectTokenProvider can be used to supply a subject token to exchange for a
|
||||||
|
// GCP access token.
|
||||||
|
type SubjectTokenProvider interface {
|
||||||
|
// SubjectToken should return a valid subject token or an error.
|
||||||
|
// The external account token provider does not cache the returned subject
|
||||||
|
// token, so caching logic should be implemented in the provider to prevent
|
||||||
|
// multiple requests for the same subject token.
|
||||||
|
SubjectToken(ctx context.Context, opts *RequestOptions) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestOptions contains information about the requested subject token or AWS
|
||||||
|
// security credentials from the Google external account credential.
|
||||||
|
type RequestOptions struct {
|
||||||
|
// Audience is the requested audience for the external account credential.
|
||||||
|
Audience string
|
||||||
|
// Subject token type is the requested subject token type for the external
|
||||||
|
// account credential. Expected values include:
|
||||||
|
// “urn:ietf:params:oauth:token-type:jwt”
|
||||||
|
// “urn:ietf:params:oauth:token-type:id-token”
|
||||||
|
// “urn:ietf:params:oauth:token-type:saml2”
|
||||||
|
// “urn:ietf:params:aws:token-type:aws4_request”
|
||||||
|
SubjectTokenType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AwsSecurityCredentialsProvider can be used to supply AwsSecurityCredentials
|
||||||
|
// and an AWS Region to exchange for a GCP access token.
|
||||||
|
type AwsSecurityCredentialsProvider interface {
|
||||||
|
// AwsRegion should return the AWS region or an error.
|
||||||
|
AwsRegion(ctx context.Context, opts *RequestOptions) (string, error)
|
||||||
|
// GetAwsSecurityCredentials should return a valid set of
|
||||||
|
// AwsSecurityCredentials or an error. The external account token provider
|
||||||
|
// does not cache the returned security credentials, so caching logic should
|
||||||
|
// be implemented in the provider to prevent multiple requests for the
|
||||||
|
// same security credentials.
|
||||||
|
AwsSecurityCredentials(ctx context.Context, opts *RequestOptions) (*AwsSecurityCredentials, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AwsSecurityCredentials models AWS security credentials.
|
||||||
|
type AwsSecurityCredentials struct {
|
||||||
|
// AccessKeyId is the AWS Access Key ID - Required.
|
||||||
|
AccessKeyID string `json:"AccessKeyID"`
|
||||||
|
// SecretAccessKey is the AWS Secret Access Key - Required.
|
||||||
|
SecretAccessKey string `json:"SecretAccessKey"`
|
||||||
|
// SessionToken is the AWS Session token. This should be provided for
|
||||||
|
// temporary AWS security credentials - Optional.
|
||||||
|
SessionToken string `json:"Token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) validate() error {
|
||||||
|
if o.Audience == "" {
|
||||||
|
return fmt.Errorf("externalaccount: Audience must be set")
|
||||||
|
}
|
||||||
|
if o.SubjectTokenType == "" {
|
||||||
|
return fmt.Errorf("externalaccount: Subject token type must be set")
|
||||||
|
}
|
||||||
|
if o.WorkforcePoolUserProject != "" {
|
||||||
|
if valid := validWorkforceAudiencePattern.MatchString(o.Audience); !valid {
|
||||||
|
return fmt.Errorf("externalaccount: workforce_pool_user_project should not be set for non-workforce pool credentials")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count := 0
|
||||||
|
if o.CredentialSource != nil {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if o.SubjectTokenProvider != nil {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if o.AwsSecurityCredentialsProvider != nil {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return fmt.Errorf("externalaccount: one of CredentialSource, SubjectTokenProvider, or AwsSecurityCredentialsProvider must be set")
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
return fmt.Errorf("externalaccount: only one of CredentialSource, SubjectTokenProvider, or AwsSecurityCredentialsProvider must be set")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// client returns the http client that should be used for the token exchange. If a non-default client
|
||||||
|
// is provided, then the client configured in the options will always be returned. If a default client
|
||||||
|
// is provided and the options are configured for X509 credentials, a new client will be created.
|
||||||
|
func (o *Options) client() (*http.Client, error) {
|
||||||
|
// If a client was provided and no override certificate config location was provided, use the provided client.
|
||||||
|
if o.CredentialSource == nil || o.CredentialSource.Certificate == nil || (!o.IsDefaultClient && o.CredentialSource.Certificate.CertificateConfigLocation == "") {
|
||||||
|
return o.Client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a new client should be created, validate and use the certificate source to create a new mTLS client.
|
||||||
|
cert := o.CredentialSource.Certificate
|
||||||
|
if !cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation == "" {
|
||||||
|
return nil, errors.New("credentials: \"certificate\" object must either specify a certificate_config_location or use_default_certificate_config should be true")
|
||||||
|
}
|
||||||
|
if cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation != "" {
|
||||||
|
return nil, errors.New("credentials: \"certificate\" object cannot specify both a certificate_config_location and use_default_certificate_config=true")
|
||||||
|
}
|
||||||
|
return createX509Client(cert.CertificateConfigLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveTokenURL sets the default STS token endpoint with the configured
|
||||||
|
// universe domain.
|
||||||
|
func (o *Options) resolveTokenURL() {
|
||||||
|
if o.TokenURL != "" {
|
||||||
|
return
|
||||||
|
} else if o.UniverseDomain != "" {
|
||||||
|
o.TokenURL = strings.Replace(defaultTokenURL, universeDomainPlaceholder, o.UniverseDomain, 1)
|
||||||
|
} else {
|
||||||
|
o.TokenURL = strings.Replace(defaultTokenURL, universeDomainPlaceholder, defaultUniverseDomain, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider]
|
||||||
|
// configured with the provided options.
|
||||||
|
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opts.resolveTokenURL()
|
||||||
|
logger := internallog.New(opts.Logger)
|
||||||
|
stp, err := newSubjectTokenProvider(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := opts.client()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := &tokenProvider{
|
||||||
|
client: client,
|
||||||
|
opts: opts,
|
||||||
|
stp: stp,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.ServiceAccountImpersonationURL == "" {
|
||||||
|
return auth.NewCachedTokenProvider(tp, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
scopes := make([]string, len(opts.Scopes))
|
||||||
|
copy(scopes, opts.Scopes)
|
||||||
|
// needed for impersonation
|
||||||
|
tp.opts.Scopes = []string{"https://www.googleapis.com/auth/cloud-platform"}
|
||||||
|
imp, err := impersonate.NewTokenProvider(&impersonate.Options{
|
||||||
|
Client: client,
|
||||||
|
URL: opts.ServiceAccountImpersonationURL,
|
||||||
|
Scopes: scopes,
|
||||||
|
Tp: auth.NewCachedTokenProvider(tp, nil),
|
||||||
|
TokenLifetimeSeconds: opts.ServiceAccountImpersonationLifetimeSeconds,
|
||||||
|
Logger: logger,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return auth.NewCachedTokenProvider(imp, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type subjectTokenProvider interface {
|
||||||
|
subjectToken(ctx context.Context) (string, error)
|
||||||
|
providerType() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenProvider is the provider that handles external credentials. It is used to retrieve Tokens.
|
||||||
|
type tokenProvider struct {
|
||||||
|
client *http.Client
|
||||||
|
logger *slog.Logger
|
||||||
|
opts *Options
|
||||||
|
stp subjectTokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
subjectToken, err := tp.stp.subjectToken(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stsRequest := &stsexchange.TokenRequest{
|
||||||
|
GrantType: stsexchange.GrantType,
|
||||||
|
Audience: tp.opts.Audience,
|
||||||
|
Scope: tp.opts.Scopes,
|
||||||
|
RequestedTokenType: stsexchange.TokenType,
|
||||||
|
SubjectToken: subjectToken,
|
||||||
|
SubjectTokenType: tp.opts.SubjectTokenType,
|
||||||
|
}
|
||||||
|
header := make(http.Header)
|
||||||
|
header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
header.Add("x-goog-api-client", getGoogHeaderValue(tp.opts, tp.stp))
|
||||||
|
clientAuth := stsexchange.ClientAuthentication{
|
||||||
|
AuthStyle: auth.StyleInHeader,
|
||||||
|
ClientID: tp.opts.ClientID,
|
||||||
|
ClientSecret: tp.opts.ClientSecret,
|
||||||
|
}
|
||||||
|
var options map[string]interface{}
|
||||||
|
// Do not pass workforce_pool_user_project when client authentication is used.
|
||||||
|
// The client ID is sufficient for determining the user project.
|
||||||
|
if tp.opts.WorkforcePoolUserProject != "" && tp.opts.ClientID == "" {
|
||||||
|
options = map[string]interface{}{
|
||||||
|
"userProject": tp.opts.WorkforcePoolUserProject,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stsResp, err := stsexchange.ExchangeToken(ctx, &stsexchange.Options{
|
||||||
|
Client: tp.client,
|
||||||
|
Endpoint: tp.opts.TokenURL,
|
||||||
|
Request: stsRequest,
|
||||||
|
Authentication: clientAuth,
|
||||||
|
Headers: header,
|
||||||
|
ExtraOpts: options,
|
||||||
|
Logger: tp.logger,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tok := &auth.Token{
|
||||||
|
Value: stsResp.AccessToken,
|
||||||
|
Type: stsResp.TokenType,
|
||||||
|
}
|
||||||
|
// The RFC8693 doesn't define the explicit 0 of "expires_in" field behavior.
|
||||||
|
if stsResp.ExpiresIn <= 0 {
|
||||||
|
return nil, fmt.Errorf("credentials: got invalid expiry from security token service")
|
||||||
|
}
|
||||||
|
tok.Expiry = Now().Add(time.Duration(stsResp.ExpiresIn) * time.Second)
|
||||||
|
return tok, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSubjectTokenProvider determines the type of credsfile.CredentialSource needed to create a
|
||||||
|
// subjectTokenProvider
|
||||||
|
func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
|
||||||
|
logger := internallog.New(o.Logger)
|
||||||
|
reqOpts := &RequestOptions{Audience: o.Audience, SubjectTokenType: o.SubjectTokenType}
|
||||||
|
if o.AwsSecurityCredentialsProvider != nil {
|
||||||
|
return &awsSubjectProvider{
|
||||||
|
securityCredentialsProvider: o.AwsSecurityCredentialsProvider,
|
||||||
|
TargetResource: o.Audience,
|
||||||
|
reqOpts: reqOpts,
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
} else if o.SubjectTokenProvider != nil {
|
||||||
|
return &programmaticProvider{stp: o.SubjectTokenProvider, opts: reqOpts}, nil
|
||||||
|
} else if len(o.CredentialSource.EnvironmentID) > 3 && o.CredentialSource.EnvironmentID[:3] == "aws" {
|
||||||
|
if awsVersion, err := strconv.Atoi(o.CredentialSource.EnvironmentID[3:]); err == nil {
|
||||||
|
if awsVersion != 1 {
|
||||||
|
return nil, fmt.Errorf("credentials: aws version '%d' is not supported in the current build", awsVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
awsProvider := &awsSubjectProvider{
|
||||||
|
EnvironmentID: o.CredentialSource.EnvironmentID,
|
||||||
|
RegionURL: o.CredentialSource.RegionURL,
|
||||||
|
RegionalCredVerificationURL: o.CredentialSource.RegionalCredVerificationURL,
|
||||||
|
CredVerificationURL: o.CredentialSource.URL,
|
||||||
|
TargetResource: o.Audience,
|
||||||
|
Client: o.Client,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
if o.CredentialSource.IMDSv2SessionTokenURL != "" {
|
||||||
|
awsProvider.IMDSv2SessionTokenURL = o.CredentialSource.IMDSv2SessionTokenURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return awsProvider, nil
|
||||||
|
}
|
||||||
|
} else if o.CredentialSource.File != "" {
|
||||||
|
return &fileSubjectProvider{File: o.CredentialSource.File, Format: o.CredentialSource.Format}, nil
|
||||||
|
} else if o.CredentialSource.URL != "" {
|
||||||
|
return &urlSubjectProvider{
|
||||||
|
URL: o.CredentialSource.URL,
|
||||||
|
Headers: o.CredentialSource.Headers,
|
||||||
|
Format: o.CredentialSource.Format,
|
||||||
|
Client: o.Client,
|
||||||
|
Logger: logger,
|
||||||
|
}, nil
|
||||||
|
} else if o.CredentialSource.Executable != nil {
|
||||||
|
ec := o.CredentialSource.Executable
|
||||||
|
if ec.Command == "" {
|
||||||
|
return nil, errors.New("credentials: missing `command` field — executable command must be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
execProvider := &executableSubjectProvider{}
|
||||||
|
execProvider.Command = ec.Command
|
||||||
|
if ec.TimeoutMillis == 0 {
|
||||||
|
execProvider.Timeout = executableDefaultTimeout
|
||||||
|
} else {
|
||||||
|
execProvider.Timeout = time.Duration(ec.TimeoutMillis) * time.Millisecond
|
||||||
|
if execProvider.Timeout < timeoutMinimum || execProvider.Timeout > timeoutMaximum {
|
||||||
|
return nil, fmt.Errorf("credentials: invalid `timeout_millis` field — executable timeout must be between %v and %v seconds", timeoutMinimum.Seconds(), timeoutMaximum.Seconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execProvider.OutputFile = ec.OutputFile
|
||||||
|
execProvider.client = o.Client
|
||||||
|
execProvider.opts = o
|
||||||
|
execProvider.env = runtimeEnvironment{}
|
||||||
|
return execProvider, nil
|
||||||
|
} else if o.CredentialSource.Certificate != nil {
|
||||||
|
cert := o.CredentialSource.Certificate
|
||||||
|
if !cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation == "" {
|
||||||
|
return nil, errors.New("credentials: \"certificate\" object must either specify a certificate_config_location or use_default_certificate_config should be true")
|
||||||
|
}
|
||||||
|
if cert.UseDefaultCertificateConfig && cert.CertificateConfigLocation != "" {
|
||||||
|
return nil, errors.New("credentials: \"certificate\" object cannot specify both a certificate_config_location and use_default_certificate_config=true")
|
||||||
|
}
|
||||||
|
return &x509Provider{
|
||||||
|
TrustChainPath: o.CredentialSource.Certificate.TrustChainPath,
|
||||||
|
ConfigFilePath: o.CredentialSource.Certificate.CertificateConfigLocation,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("credentials: unable to parse credential source")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGoogHeaderValue(conf *Options, p subjectTokenProvider) string {
|
||||||
|
return fmt.Sprintf("gl-go/%s auth/%s google-byoid-sdk source/%s sa-impersonation/%t config-lifetime/%t",
|
||||||
|
goVersion(),
|
||||||
|
"unknown",
|
||||||
|
p.providerType(),
|
||||||
|
conf.ServiceAccountImpersonationURL != "",
|
||||||
|
conf.ServiceAccountImpersonationLifetimeSeconds != 0)
|
||||||
|
}
|
||||||
78
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/file_provider.go
generated
vendored
Normal file
78
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/file_provider.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fileProviderType = "file"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileSubjectProvider struct {
|
||||||
|
File string
|
||||||
|
Format *credsfile.Format
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *fileSubjectProvider) subjectToken(context.Context) (string, error) {
|
||||||
|
tokenFile, err := os.Open(sp.File)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: failed to open credential file %q: %w", sp.File, err)
|
||||||
|
}
|
||||||
|
defer tokenFile.Close()
|
||||||
|
tokenBytes, err := internal.ReadAll(tokenFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: failed to read credential file: %w", err)
|
||||||
|
}
|
||||||
|
tokenBytes = bytes.TrimSpace(tokenBytes)
|
||||||
|
|
||||||
|
if sp.Format == nil {
|
||||||
|
return string(tokenBytes), nil
|
||||||
|
}
|
||||||
|
switch sp.Format.Type {
|
||||||
|
case fileTypeJSON:
|
||||||
|
jsonData := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(tokenBytes, &jsonData)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: failed to unmarshal subject token file: %w", err)
|
||||||
|
}
|
||||||
|
val, ok := jsonData[sp.Format.SubjectTokenFieldName]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("credentials: provided subject_token_field_name not found in credentials")
|
||||||
|
}
|
||||||
|
token, ok := val.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("credentials: improperly formatted subject token")
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
case fileTypeText:
|
||||||
|
return string(tokenBytes), nil
|
||||||
|
default:
|
||||||
|
return "", errors.New("credentials: invalid credential_source file format type: " + sp.Format.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *fileSubjectProvider) providerType() string {
|
||||||
|
return fileProviderType
|
||||||
|
}
|
||||||
74
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/info.go
generated
vendored
Normal file
74
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/info.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// version is a package internal global variable for testing purposes.
|
||||||
|
version = runtime.Version
|
||||||
|
)
|
||||||
|
|
||||||
|
// versionUnknown is only used when the runtime version cannot be determined.
|
||||||
|
const versionUnknown = "UNKNOWN"
|
||||||
|
|
||||||
|
// goVersion returns a Go runtime version derived from the runtime environment
|
||||||
|
// that is modified to be suitable for reporting in a header, meaning it has no
|
||||||
|
// whitespace. If it is unable to determine the Go runtime version, it returns
|
||||||
|
// versionUnknown.
|
||||||
|
func goVersion() string {
|
||||||
|
const develPrefix = "devel +"
|
||||||
|
|
||||||
|
s := version()
|
||||||
|
if strings.HasPrefix(s, develPrefix) {
|
||||||
|
s = s[len(develPrefix):]
|
||||||
|
if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
||||||
|
s = s[:p]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
} else if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
||||||
|
s = s[:p]
|
||||||
|
}
|
||||||
|
|
||||||
|
notSemverRune := func(r rune) bool {
|
||||||
|
return !strings.ContainsRune("0123456789.", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s, "go1") {
|
||||||
|
s = s[2:]
|
||||||
|
var prerelease string
|
||||||
|
if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
|
||||||
|
s, prerelease = s[:p], s[p:]
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(s, ".") {
|
||||||
|
s += "0"
|
||||||
|
} else if strings.Count(s, ".") < 2 {
|
||||||
|
s += ".0"
|
||||||
|
}
|
||||||
|
if prerelease != "" {
|
||||||
|
// Some release candidates already have a dash in them.
|
||||||
|
if !strings.HasPrefix(prerelease, "-") {
|
||||||
|
prerelease = "-" + prerelease
|
||||||
|
}
|
||||||
|
s += prerelease
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return versionUnknown
|
||||||
|
}
|
||||||
30
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/programmatic_provider.go
generated
vendored
Normal file
30
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/programmatic_provider.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2024 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 externalaccount
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type programmaticProvider struct {
|
||||||
|
opts *RequestOptions
|
||||||
|
stp SubjectTokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *programmaticProvider) providerType() string {
|
||||||
|
return programmaticProviderType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *programmaticProvider) subjectToken(ctx context.Context) (string, error) {
|
||||||
|
return pp.stp.SubjectToken(ctx, pp.opts)
|
||||||
|
}
|
||||||
93
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/url_provider.go
generated
vendored
Normal file
93
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/url_provider.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2023 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fileTypeText = "text"
|
||||||
|
fileTypeJSON = "json"
|
||||||
|
urlProviderType = "url"
|
||||||
|
programmaticProviderType = "programmatic"
|
||||||
|
x509ProviderType = "x509"
|
||||||
|
)
|
||||||
|
|
||||||
|
type urlSubjectProvider struct {
|
||||||
|
URL string
|
||||||
|
Headers map[string]string
|
||||||
|
Format *credsfile.Format
|
||||||
|
Client *http.Client
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", sp.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: HTTP request for URL-sourced credential failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, val := range sp.Headers {
|
||||||
|
req.Header.Add(key, val)
|
||||||
|
}
|
||||||
|
sp.Logger.DebugContext(ctx, "url subject token request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: invalid response when retrieving subject token: %w", err)
|
||||||
|
}
|
||||||
|
sp.Logger.DebugContext(ctx, "url subject token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||||
|
return "", fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp.Format == nil {
|
||||||
|
return string(body), nil
|
||||||
|
}
|
||||||
|
switch sp.Format.Type {
|
||||||
|
case "json":
|
||||||
|
jsonData := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(body, &jsonData)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("credentials: failed to unmarshal subject token file: %w", err)
|
||||||
|
}
|
||||||
|
val, ok := jsonData[sp.Format.SubjectTokenFieldName]
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("credentials: provided subject_token_field_name not found in credentials")
|
||||||
|
}
|
||||||
|
token, ok := val.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("credentials: improperly formatted subject token")
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
case fileTypeText:
|
||||||
|
return string(body), nil
|
||||||
|
default:
|
||||||
|
return "", errors.New("credentials: invalid credential_source file format type: " + sp.Format.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *urlSubjectProvider) providerType() string {
|
||||||
|
return urlProviderType
|
||||||
|
}
|
||||||
220
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/x509_provider.go
generated
vendored
Normal file
220
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/x509_provider.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
// Copyright 2024 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 externalaccount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal/transport/cert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// x509Provider implements the subjectTokenProvider type for x509 workload
|
||||||
|
// identity credentials. This provider retrieves and formats a JSON array
|
||||||
|
// containing the leaf certificate and trust chain (if provided) as
|
||||||
|
// base64-encoded strings. This JSON array serves as the subject token for
|
||||||
|
// mTLS authentication.
|
||||||
|
type x509Provider struct {
|
||||||
|
// TrustChainPath is the path to the file containing the trust chain certificates.
|
||||||
|
// The file should contain one or more PEM-encoded certificates.
|
||||||
|
TrustChainPath string
|
||||||
|
// ConfigFilePath is the path to the configuration file containing the path
|
||||||
|
// to the leaf certificate file.
|
||||||
|
ConfigFilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
const pemCertificateHeader = "-----BEGIN CERTIFICATE-----"
|
||||||
|
|
||||||
|
func (xp *x509Provider) providerType() string {
|
||||||
|
return x509ProviderType
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadLeafCertificate loads and parses the leaf certificate from the specified
|
||||||
|
// configuration file. It retrieves the certificate path from the config file,
|
||||||
|
// reads the certificate file, and parses the certificate data.
|
||||||
|
func loadLeafCertificate(configFilePath string) (*x509.Certificate, error) {
|
||||||
|
// Get the path to the certificate file from the configuration file.
|
||||||
|
path, err := cert.GetCertificatePath(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get certificate path from config file: %w", err)
|
||||||
|
}
|
||||||
|
leafCertBytes, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read leaf certificate file: %w", err)
|
||||||
|
}
|
||||||
|
// Parse the certificate bytes.
|
||||||
|
return parseCertificate(leafCertBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeCert encodes a x509.Certificate to a base64 string.
|
||||||
|
func encodeCert(cert *x509.Certificate) string {
|
||||||
|
// cert.Raw contains the raw DER-encoded certificate. Encode the raw certificate bytes to base64.
|
||||||
|
return base64.StdEncoding.EncodeToString(cert.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseCertificate parses a PEM-encoded certificate from the given byte slice.
|
||||||
|
func parseCertificate(certData []byte) (*x509.Certificate, error) {
|
||||||
|
if len(certData) == 0 {
|
||||||
|
return nil, errors.New("invalid certificate data: empty input")
|
||||||
|
}
|
||||||
|
// Decode the PEM-encoded data.
|
||||||
|
block, _ := pem.Decode(certData)
|
||||||
|
if block == nil {
|
||||||
|
return nil, errors.New("invalid PEM-encoded certificate data: no PEM block found")
|
||||||
|
}
|
||||||
|
if block.Type != "CERTIFICATE" {
|
||||||
|
return nil, fmt.Errorf("invalid PEM-encoded certificate data: expected CERTIFICATE block type, got %s", block.Type)
|
||||||
|
}
|
||||||
|
// Parse the DER-encoded certificate.
|
||||||
|
certificate, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse certificate: %w", err)
|
||||||
|
}
|
||||||
|
return certificate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readTrustChain reads a file of PEM-encoded X.509 certificates and returns a slice of parsed certificates.
|
||||||
|
// It splits the file content into PEM certificate blocks and parses each one.
|
||||||
|
func readTrustChain(trustChainPath string) ([]*x509.Certificate, error) {
|
||||||
|
certificateTrustChain := []*x509.Certificate{}
|
||||||
|
|
||||||
|
// If no trust chain path is provided, return an empty slice.
|
||||||
|
if trustChainPath == "" {
|
||||||
|
return certificateTrustChain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the trust chain file.
|
||||||
|
trustChainData, err := os.ReadFile(trustChainPath)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return nil, fmt.Errorf("trust chain file not found: %w", err)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to read trust chain file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the file content into PEM certificate blocks.
|
||||||
|
certBlocks := strings.Split(string(trustChainData), pemCertificateHeader)
|
||||||
|
|
||||||
|
// Iterate over each certificate block.
|
||||||
|
for _, certBlock := range certBlocks {
|
||||||
|
// Trim whitespace from the block.
|
||||||
|
certBlock = strings.TrimSpace(certBlock)
|
||||||
|
|
||||||
|
if certBlock != "" {
|
||||||
|
// Add the PEM header to the block.
|
||||||
|
certData := pemCertificateHeader + "\n" + certBlock
|
||||||
|
|
||||||
|
// Parse the certificate data.
|
||||||
|
cert, err := parseCertificate([]byte(certData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing certificate from trust chain file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the certificate to the trust chain.
|
||||||
|
certificateTrustChain = append(certificateTrustChain, cert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificateTrustChain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// subjectToken retrieves the X.509 subject token. It loads the leaf
|
||||||
|
// certificate and, if a trust chain path is configured, the trust chain
|
||||||
|
// certificates. It then constructs a JSON array containing the base64-encoded
|
||||||
|
// leaf certificate and each base64-encoded certificate in the trust chain.
|
||||||
|
// The leaf certificate must be at the top of the trust chain file. This JSON
|
||||||
|
// array is used as the subject token for mTLS authentication.
|
||||||
|
func (xp *x509Provider) subjectToken(context.Context) (string, error) {
|
||||||
|
// Load the leaf certificate.
|
||||||
|
leafCert, err := loadLeafCertificate(xp.ConfigFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to load leaf certificate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the trust chain.
|
||||||
|
trustChain, err := readTrustChain(xp.TrustChainPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to read trust chain: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the certificate chain with the leaf certificate.
|
||||||
|
certChain := []string{encodeCert(leafCert)}
|
||||||
|
|
||||||
|
// If there is a trust chain, add certificates to the certificate chain.
|
||||||
|
if len(trustChain) > 0 {
|
||||||
|
firstCert := encodeCert(trustChain[0])
|
||||||
|
|
||||||
|
// If the first certificate in the trust chain is not the same as the leaf certificate, add it to the chain.
|
||||||
|
if firstCert != certChain[0] {
|
||||||
|
certChain = append(certChain, firstCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the remaining certificates in the trust chain.
|
||||||
|
for i := 1; i < len(trustChain); i++ {
|
||||||
|
encoded := encodeCert(trustChain[i])
|
||||||
|
|
||||||
|
// Return an error if the current certificate is the same as the leaf certificate.
|
||||||
|
if encoded == certChain[0] {
|
||||||
|
return "", errors.New("the leaf certificate must be at the top of the trust chain file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the current certificate to the chain.
|
||||||
|
certChain = append(certChain, encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the certificate chain to a JSON array of base64-encoded strings.
|
||||||
|
jsonChain, err := json.Marshal(certChain)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to format certificate data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the JSON-formatted certificate chain.
|
||||||
|
return string(jsonChain), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// createX509Client creates a new client that is configured with mTLS, using the
|
||||||
|
// certificate configuration specified in the credential source.
|
||||||
|
func createX509Client(certificateConfigLocation string) (*http.Client, error) {
|
||||||
|
certProvider, err := cert.NewWorkloadX509CertProvider(certificateConfigLocation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
trans := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
|
||||||
|
trans.TLSClientConfig = &tls.Config{
|
||||||
|
GetClientCertificate: certProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a client with default settings plus the X509 workload cert and key.
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: trans,
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
115
vendor/cloud.google.com/go/auth/credentials/internal/externalaccountuser/externalaccountuser.go
generated
vendored
Normal file
115
vendor/cloud.google.com/go/auth/credentials/internal/externalaccountuser/externalaccountuser.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright 2023 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 externalaccountuser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options stores the configuration for fetching tokens with external authorized
|
||||||
|
// user credentials.
|
||||||
|
type Options struct {
|
||||||
|
// Audience is the Secure Token Service (STS) audience which contains the
|
||||||
|
// resource name for the workforce pool and the provider identifier in that
|
||||||
|
// pool.
|
||||||
|
Audience string
|
||||||
|
// RefreshToken is the OAuth 2.0 refresh token.
|
||||||
|
RefreshToken string
|
||||||
|
// TokenURL is the STS token exchange endpoint for refresh.
|
||||||
|
TokenURL string
|
||||||
|
// TokenInfoURL is the STS endpoint URL for token introspection. Optional.
|
||||||
|
TokenInfoURL string
|
||||||
|
// ClientID is only required in conjunction with ClientSecret, as described
|
||||||
|
// below.
|
||||||
|
ClientID string
|
||||||
|
// ClientSecret is currently only required if token_info endpoint also needs
|
||||||
|
// to be called with the generated a cloud access token. When provided, STS
|
||||||
|
// will be called with additional basic authentication using client_id as
|
||||||
|
// username and client_secret as password.
|
||||||
|
ClientSecret string
|
||||||
|
// Scopes contains the desired scopes for the returned access token.
|
||||||
|
Scopes []string
|
||||||
|
|
||||||
|
// Client for token request.
|
||||||
|
Client *http.Client
|
||||||
|
// Logger for logging.
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Options) validate() bool {
|
||||||
|
return c.ClientID != "" && c.ClientSecret != "" && c.RefreshToken != "" && c.TokenURL != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider]
|
||||||
|
// configured with the provided options.
|
||||||
|
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||||
|
if !opts.validate() {
|
||||||
|
return nil, errors.New("credentials: invalid external_account_authorized_user configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := &tokenProvider{
|
||||||
|
o: opts,
|
||||||
|
}
|
||||||
|
return auth.NewCachedTokenProvider(tp, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenProvider struct {
|
||||||
|
o *Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
opts := tp.o
|
||||||
|
|
||||||
|
clientAuth := stsexchange.ClientAuthentication{
|
||||||
|
AuthStyle: auth.StyleInHeader,
|
||||||
|
ClientID: opts.ClientID,
|
||||||
|
ClientSecret: opts.ClientSecret,
|
||||||
|
}
|
||||||
|
headers := make(http.Header)
|
||||||
|
headers.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
stsResponse, err := stsexchange.RefreshAccessToken(ctx, &stsexchange.Options{
|
||||||
|
Client: opts.Client,
|
||||||
|
Endpoint: opts.TokenURL,
|
||||||
|
RefreshToken: opts.RefreshToken,
|
||||||
|
Authentication: clientAuth,
|
||||||
|
Headers: headers,
|
||||||
|
Logger: internallog.New(tp.o.Logger),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if stsResponse.ExpiresIn < 0 {
|
||||||
|
return nil, errors.New("credentials: invalid expiry from security token service")
|
||||||
|
}
|
||||||
|
|
||||||
|
// guarded by the wrapping with CachedTokenProvider
|
||||||
|
if stsResponse.RefreshToken != "" {
|
||||||
|
opts.RefreshToken = stsResponse.RefreshToken
|
||||||
|
}
|
||||||
|
return &auth.Token{
|
||||||
|
Value: stsResponse.AccessToken,
|
||||||
|
Expiry: time.Now().UTC().Add(time.Duration(stsResponse.ExpiresIn) * time.Second),
|
||||||
|
Type: internal.TokenTypeBearer,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
191
vendor/cloud.google.com/go/auth/credentials/internal/gdch/gdch.go
generated
vendored
Normal file
191
vendor/cloud.google.com/go/auth/credentials/internal/gdch/gdch.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Copyright 2023 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 gdch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"cloud.google.com/go/auth/internal/jwt"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GrantType is the grant type for the token request.
|
||||||
|
GrantType = "urn:ietf:params:oauth:token-type:token-exchange"
|
||||||
|
requestTokenType = "urn:ietf:params:oauth:token-type:access_token"
|
||||||
|
subjectTokenType = "urn:k8s:params:oauth:token-type:serviceaccount"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
gdchSupportFormatVersions map[string]bool = map[string]bool{
|
||||||
|
"1": true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options for [NewTokenProvider].
|
||||||
|
type Options struct {
|
||||||
|
STSAudience string
|
||||||
|
Client *http.Client
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider] from a
|
||||||
|
// GDCH cred file.
|
||||||
|
func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.TokenProvider, error) {
|
||||||
|
if !gdchSupportFormatVersions[f.FormatVersion] {
|
||||||
|
return nil, fmt.Errorf("credentials: unsupported gdch_service_account format %q", f.FormatVersion)
|
||||||
|
}
|
||||||
|
if o.STSAudience == "" {
|
||||||
|
return nil, errors.New("credentials: STSAudience must be set for the GDCH auth flows")
|
||||||
|
}
|
||||||
|
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
certPool, err := loadCertPool(f.CertPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := gdchProvider{
|
||||||
|
serviceIdentity: fmt.Sprintf("system:serviceaccount:%s:%s", f.Project, f.Name),
|
||||||
|
tokenURL: f.TokenURL,
|
||||||
|
aud: o.STSAudience,
|
||||||
|
signer: signer,
|
||||||
|
pkID: f.PrivateKeyID,
|
||||||
|
certPool: certPool,
|
||||||
|
client: o.Client,
|
||||||
|
logger: internallog.New(o.Logger),
|
||||||
|
}
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCertPool(path string) (*x509.CertPool, error) {
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
pem, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: failed to read certificate: %w", err)
|
||||||
|
}
|
||||||
|
pool.AppendCertsFromPEM(pem)
|
||||||
|
return pool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type gdchProvider struct {
|
||||||
|
serviceIdentity string
|
||||||
|
tokenURL string
|
||||||
|
aud string
|
||||||
|
signer crypto.Signer
|
||||||
|
pkID string
|
||||||
|
certPool *x509.CertPool
|
||||||
|
|
||||||
|
client *http.Client
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
addCertToTransport(g.client, g.certPool)
|
||||||
|
iat := time.Now()
|
||||||
|
exp := iat.Add(time.Hour)
|
||||||
|
claims := jwt.Claims{
|
||||||
|
Iss: g.serviceIdentity,
|
||||||
|
Sub: g.serviceIdentity,
|
||||||
|
Aud: g.tokenURL,
|
||||||
|
Iat: iat.Unix(),
|
||||||
|
Exp: exp.Unix(),
|
||||||
|
}
|
||||||
|
h := jwt.Header{
|
||||||
|
Algorithm: jwt.HeaderAlgRSA256,
|
||||||
|
Type: jwt.HeaderType,
|
||||||
|
KeyID: string(g.pkID),
|
||||||
|
}
|
||||||
|
payload, err := jwt.EncodeJWS(&h, &claims, g.signer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("grant_type", GrantType)
|
||||||
|
v.Set("audience", g.aud)
|
||||||
|
v.Set("requested_token_type", requestTokenType)
|
||||||
|
v.Set("subject_token", payload)
|
||||||
|
v.Set("subject_token_type", subjectTokenType)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", g.tokenURL, strings.NewReader(v.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||||
|
resp, body, err := internal.DoRequest(g.client, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
||||||
|
}
|
||||||
|
g.logger.DebugContext(ctx, "gdch token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
||||||
|
return nil, &auth.Error{
|
||||||
|
Response: resp,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenRes struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
ExpiresIn int64 `json:"expires_in"` // relative seconds from now
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &tokenRes); err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
||||||
|
}
|
||||||
|
token := &auth.Token{
|
||||||
|
Value: tokenRes.AccessToken,
|
||||||
|
Type: tokenRes.TokenType,
|
||||||
|
}
|
||||||
|
raw := make(map[string]interface{})
|
||||||
|
json.Unmarshal(body, &raw) // no error checks for optional fields
|
||||||
|
token.Metadata = raw
|
||||||
|
|
||||||
|
if secs := tokenRes.ExpiresIn; secs > 0 {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addCertToTransport makes a best effort attempt at adding in the cert info to
|
||||||
|
// the client. It tries to keep all configured transport settings if the
|
||||||
|
// underlying transport is an http.Transport. Or else it overwrites the
|
||||||
|
// transport with defaults adding in the certs.
|
||||||
|
func addCertToTransport(hc *http.Client, certPool *x509.CertPool) {
|
||||||
|
trans, ok := hc.Transport.(*http.Transport)
|
||||||
|
if !ok {
|
||||||
|
trans = http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
}
|
||||||
|
trans.TLSClientConfig = &tls.Config{
|
||||||
|
RootCAs: certPool,
|
||||||
|
}
|
||||||
|
}
|
||||||
105
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/idtoken.go
generated
vendored
Normal file
105
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/idtoken.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// Copyright 2025 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 impersonate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
||||||
|
iamCredentialsUniverseDomainEndpoint = "https://iamcredentials.UNIVERSE_DOMAIN"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IDTokenIAMOptions provides configuration for [IDTokenIAMOptions.Token].
|
||||||
|
type IDTokenIAMOptions struct {
|
||||||
|
// Client is required.
|
||||||
|
Client *http.Client
|
||||||
|
// Logger is required.
|
||||||
|
Logger *slog.Logger
|
||||||
|
UniverseDomain auth.CredentialsPropertyProvider
|
||||||
|
ServiceAccountEmail string
|
||||||
|
GenerateIDTokenRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIDTokenRequest holds the request to the IAM generateIdToken RPC.
|
||||||
|
type GenerateIDTokenRequest struct {
|
||||||
|
Audience string `json:"audience"`
|
||||||
|
IncludeEmail bool `json:"includeEmail"`
|
||||||
|
// Delegates are the ordered, fully-qualified resource name for service
|
||||||
|
// accounts in a delegation chain. Each service account must be granted
|
||||||
|
// roles/iam.serviceAccountTokenCreator on the next service account in the
|
||||||
|
// chain. The delegates must have the following format:
|
||||||
|
// projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}. The - wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
// Optional.
|
||||||
|
Delegates []string `json:"delegates,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIDTokenResponse holds the response from the IAM generateIdToken RPC.
|
||||||
|
type GenerateIDTokenResponse struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token call IAM generateIdToken with the configuration provided in [IDTokenIAMOptions].
|
||||||
|
func (o IDTokenIAMOptions) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
universeDomain, err := o.UniverseDomain.GetProperty(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
endpoint := strings.Replace(iamCredentialsUniverseDomainEndpoint, universeDomainPlaceholder, universeDomain, 1)
|
||||||
|
url := fmt.Sprintf("%s/v1/%s:generateIdToken", endpoint, internal.FormatIAMServiceAccountResource(o.ServiceAccountEmail))
|
||||||
|
|
||||||
|
bodyBytes, err := json.Marshal(o.GenerateIDTokenRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("impersonate: unable to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(bodyBytes))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("impersonate: unable to create request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
o.Logger.DebugContext(ctx, "impersonated idtoken request", "request", internallog.HTTPRequest(req, bodyBytes))
|
||||||
|
resp, body, err := internal.DoRequest(o.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("impersonate: unable to generate ID token: %w", err)
|
||||||
|
}
|
||||||
|
o.Logger.DebugContext(ctx, "impersonated idtoken response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < 200 || c > 299 {
|
||||||
|
return nil, fmt.Errorf("impersonate: status code %d: %s", c, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenResp GenerateIDTokenResponse
|
||||||
|
if err := json.Unmarshal(body, &tokenResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("impersonate: unable to parse response: %w", err)
|
||||||
|
}
|
||||||
|
return &auth.Token{
|
||||||
|
Value: tokenResp.Token,
|
||||||
|
// Generated ID tokens are good for one hour.
|
||||||
|
Expiry: time.Now().Add(1 * time.Hour),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
168
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/impersonate.go
generated
vendored
Normal file
168
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/impersonate.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
// Copyright 2023 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 impersonate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/headers"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultTokenLifetime = "3600s"
|
||||||
|
authHeaderKey = "Authorization"
|
||||||
|
)
|
||||||
|
|
||||||
|
var serviceAccountEmailRegex = regexp.MustCompile(`serviceAccounts/(.+?):generateAccessToken`)
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokenProvider uses a source credential, stored in Ts, to request an access token to the provided URL.
|
||||||
|
// Scopes can be defined when the access token is requested.
|
||||||
|
func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options for [NewTokenProvider].
|
||||||
|
type Options struct {
|
||||||
|
// Tp is the source credential used to generate a token on the
|
||||||
|
// impersonated service account. Required.
|
||||||
|
Tp auth.TokenProvider
|
||||||
|
|
||||||
|
// URL is the endpoint to call to generate a token
|
||||||
|
// on behalf of the service account. Required.
|
||||||
|
URL string
|
||||||
|
// Scopes that the impersonated credential should have. Required.
|
||||||
|
Scopes []string
|
||||||
|
// Delegates are the service account email addresses in a delegation chain.
|
||||||
|
// Each service account must be granted roles/iam.serviceAccountTokenCreator
|
||||||
|
// on the next service account in the chain. Optional.
|
||||||
|
Delegates []string
|
||||||
|
// TokenLifetimeSeconds is the number of seconds the impersonation token will
|
||||||
|
// be valid for. Defaults to 1 hour if unset. Optional.
|
||||||
|
TokenLifetimeSeconds int
|
||||||
|
// Client configures the underlying client used to make network requests
|
||||||
|
// when fetching tokens. Required.
|
||||||
|
Client *http.Client
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
UniverseDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) validate() error {
|
||||||
|
if o.Tp == nil {
|
||||||
|
return errors.New("credentials: missing required 'source_credentials' field in impersonated credentials")
|
||||||
|
}
|
||||||
|
if o.URL == "" {
|
||||||
|
return errors.New("credentials: missing required 'service_account_impersonation_url' field in impersonated credentials")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token performs the exchange to get a temporary service account token to allow access to GCP.
|
||||||
|
func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
logger := internallog.New(o.Logger)
|
||||||
|
lifetime := defaultTokenLifetime
|
||||||
|
if o.TokenLifetimeSeconds != 0 {
|
||||||
|
lifetime = fmt.Sprintf("%ds", o.TokenLifetimeSeconds)
|
||||||
|
}
|
||||||
|
reqBody := generateAccessTokenReq{
|
||||||
|
Lifetime: lifetime,
|
||||||
|
Scope: o.Scopes,
|
||||||
|
Delegates: o.Delegates,
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: unable to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", o.URL, bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: unable to create impersonation request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
sourceToken, err := o.Tp.Token(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headers.SetAuthHeader(sourceToken, req)
|
||||||
|
logger.DebugContext(ctx, "impersonated token request", "request", internallog.HTTPRequest(req, b))
|
||||||
|
resp, body, err := internal.DoRequest(o.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: unable to generate access token: %w", err)
|
||||||
|
}
|
||||||
|
logger.DebugContext(ctx, "impersonated token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||||
|
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessTokenResp impersonateTokenResponse
|
||||||
|
if err := json.Unmarshal(body, &accessTokenResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: unable to parse response: %w", err)
|
||||||
|
}
|
||||||
|
expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: unable to parse expiry: %w", err)
|
||||||
|
}
|
||||||
|
token := &auth.Token{
|
||||||
|
Value: accessTokenResp.AccessToken,
|
||||||
|
Expiry: expiry,
|
||||||
|
Type: internal.TokenTypeBearer,
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServiceAccountEmail extracts the service account email from the impersonation URL.
|
||||||
|
// The impersonation URL is expected to be in the format:
|
||||||
|
// https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{SERVICE_ACCOUNT_EMAIL}:generateAccessToken
|
||||||
|
// or
|
||||||
|
// https://iamcredentials.googleapis.com/v1/projects/{PROJECT_ID}/serviceAccounts/{SERVICE_ACCOUNT_EMAIL}:generateAccessToken
|
||||||
|
// Returns an error if the email cannot be extracted.
|
||||||
|
func ExtractServiceAccountEmail(impersonationURL string) (string, error) {
|
||||||
|
matches := serviceAccountEmailRegex.FindStringSubmatch(impersonationURL)
|
||||||
|
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return "", fmt.Errorf("credentials: invalid impersonation URL format: %s", impersonationURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches[1], nil
|
||||||
|
}
|
||||||
167
vendor/cloud.google.com/go/auth/credentials/internal/stsexchange/sts_exchange.go
generated
vendored
Normal file
167
vendor/cloud.google.com/go/auth/credentials/internal/stsexchange/sts_exchange.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
// Copyright 2023 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 stsexchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GrantType for a sts exchange.
|
||||||
|
GrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
|
||||||
|
// TokenType for a sts exchange.
|
||||||
|
TokenType = "urn:ietf:params:oauth:token-type:access_token"
|
||||||
|
|
||||||
|
jwtTokenType = "urn:ietf:params:oauth:token-type:jwt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options stores the configuration for making an sts exchange request.
|
||||||
|
type Options struct {
|
||||||
|
Client *http.Client
|
||||||
|
Logger *slog.Logger
|
||||||
|
Endpoint string
|
||||||
|
Request *TokenRequest
|
||||||
|
Authentication ClientAuthentication
|
||||||
|
Headers http.Header
|
||||||
|
// ExtraOpts are optional fields marshalled into the `options` field of the
|
||||||
|
// request body.
|
||||||
|
ExtraOpts map[string]interface{}
|
||||||
|
RefreshToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshAccessToken performs the token exchange using a refresh token flow.
|
||||||
|
func RefreshAccessToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("grant_type", "refresh_token")
|
||||||
|
data.Set("refresh_token", opts.RefreshToken)
|
||||||
|
return doRequest(ctx, opts, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExchangeToken performs an oauth2 token exchange with the provided endpoint.
|
||||||
|
func ExchangeToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("audience", opts.Request.Audience)
|
||||||
|
data.Set("grant_type", GrantType)
|
||||||
|
data.Set("requested_token_type", TokenType)
|
||||||
|
data.Set("subject_token_type", opts.Request.SubjectTokenType)
|
||||||
|
data.Set("subject_token", opts.Request.SubjectToken)
|
||||||
|
data.Set("scope", strings.Join(opts.Request.Scope, " "))
|
||||||
|
if opts.ExtraOpts != nil {
|
||||||
|
opts, err := json.Marshal(opts.ExtraOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: failed to marshal additional options: %w", err)
|
||||||
|
}
|
||||||
|
data.Set("options", string(opts))
|
||||||
|
}
|
||||||
|
return doRequest(ctx, opts, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenResponse, error) {
|
||||||
|
opts.Authentication.InjectAuthentication(data, opts.Headers)
|
||||||
|
encodedData := data.Encode()
|
||||||
|
logger := internallog.New(opts.Logger)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", opts.Endpoint, strings.NewReader(encodedData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: failed to properly build http request: %w", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
for key, list := range opts.Headers {
|
||||||
|
for _, val := range list {
|
||||||
|
req.Header.Add(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Length", strconv.Itoa(len(encodedData)))
|
||||||
|
|
||||||
|
logger.DebugContext(ctx, "sts token request", "request", internallog.HTTPRequest(req, []byte(encodedData)))
|
||||||
|
resp, body, err := internal.DoRequest(opts.Client, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: invalid response from Secure Token Server: %w", err)
|
||||||
|
}
|
||||||
|
logger.DebugContext(ctx, "sts token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
||||||
|
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||||
|
}
|
||||||
|
var stsResp TokenResponse
|
||||||
|
if err := json.Unmarshal(body, &stsResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: failed to unmarshal response body from Secure Token Server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stsResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenRequest contains fields necessary to make an oauth2 token
|
||||||
|
// exchange.
|
||||||
|
type TokenRequest struct {
|
||||||
|
ActingParty struct {
|
||||||
|
ActorToken string
|
||||||
|
ActorTokenType string
|
||||||
|
}
|
||||||
|
GrantType string
|
||||||
|
Resource string
|
||||||
|
Audience string
|
||||||
|
Scope []string
|
||||||
|
RequestedTokenType string
|
||||||
|
SubjectToken string
|
||||||
|
SubjectTokenType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenResponse is used to decode the remote server response during
|
||||||
|
// an oauth2 token exchange.
|
||||||
|
type TokenResponse 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 auth.Style
|
||||||
|
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 auth.StyleInHeader:
|
||||||
|
plainHeader := c.ClientID + ":" + c.ClientSecret
|
||||||
|
headers.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(plainHeader)))
|
||||||
|
default:
|
||||||
|
values.Set("client_id", c.ClientID)
|
||||||
|
values.Set("client_secret", c.ClientSecret)
|
||||||
|
}
|
||||||
|
}
|
||||||
89
vendor/cloud.google.com/go/auth/credentials/selfsignedjwt.go
generated
vendored
Normal file
89
vendor/cloud.google.com/go/auth/credentials/selfsignedjwt.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2023 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 credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/credsfile"
|
||||||
|
"cloud.google.com/go/auth/internal/jwt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// for testing
|
||||||
|
now func() time.Time = time.Now
|
||||||
|
)
|
||||||
|
|
||||||
|
// configureSelfSignedJWT uses the private key in the service account to create
|
||||||
|
// a JWT without making a network call.
|
||||||
|
func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||||
|
if len(opts.scopes()) == 0 && opts.Audience == "" {
|
||||||
|
return nil, errors.New("credentials: both scopes and audience are empty")
|
||||||
|
}
|
||||||
|
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: could not parse key: %w", err)
|
||||||
|
}
|
||||||
|
return &selfSignedTokenProvider{
|
||||||
|
email: f.ClientEmail,
|
||||||
|
audience: opts.Audience,
|
||||||
|
scopes: opts.scopes(),
|
||||||
|
signer: signer,
|
||||||
|
pkID: f.PrivateKeyID,
|
||||||
|
logger: opts.logger(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type selfSignedTokenProvider struct {
|
||||||
|
email string
|
||||||
|
audience string
|
||||||
|
scopes []string
|
||||||
|
signer crypto.Signer
|
||||||
|
pkID string
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
|
||||||
|
iat := now()
|
||||||
|
exp := iat.Add(time.Hour)
|
||||||
|
scope := strings.Join(tp.scopes, " ")
|
||||||
|
c := &jwt.Claims{
|
||||||
|
Iss: tp.email,
|
||||||
|
Sub: tp.email,
|
||||||
|
Aud: tp.audience,
|
||||||
|
Scope: scope,
|
||||||
|
Iat: iat.Unix(),
|
||||||
|
Exp: exp.Unix(),
|
||||||
|
}
|
||||||
|
h := &jwt.Header{
|
||||||
|
Algorithm: jwt.HeaderAlgRSA256,
|
||||||
|
Type: jwt.HeaderType,
|
||||||
|
KeyID: string(tp.pkID),
|
||||||
|
}
|
||||||
|
tok, err := jwt.EncodeJWS(h, c, tp.signer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credentials: could not encode JWT: %w", err)
|
||||||
|
}
|
||||||
|
tp.logger.Debug("created self-signed JWT", "token", tok)
|
||||||
|
return &auth.Token{Value: tok, Type: internal.TokenTypeBearer, Expiry: exp}, nil
|
||||||
|
}
|
||||||
62
vendor/cloud.google.com/go/auth/grpctransport/dial_socketopt.go
generated
vendored
Normal file
62
vendor/cloud.google.com/go/auth/grpctransport/dial_socketopt.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2023 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 grpctransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defaultTCPUserTimeout is the default TCP_USER_TIMEOUT socket option. By
|
||||||
|
// default is 20 seconds.
|
||||||
|
tcpUserTimeoutMilliseconds = 20000
|
||||||
|
|
||||||
|
// Copied from golang.org/x/sys/unix.TCP_USER_TIMEOUT.
|
||||||
|
tcpUserTimeoutOp = 0x12
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// timeoutDialerOption is a grpc.DialOption that contains dialer with
|
||||||
|
// socket option TCP_USER_TIMEOUT. This dialer requires go versions 1.11+.
|
||||||
|
timeoutDialerOption = grpc.WithContextDialer(dialTCPUserTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialTCPUserTimeout(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
|
control := func(network, address string, c syscall.RawConn) error {
|
||||||
|
var syscallErr error
|
||||||
|
controlErr := c.Control(func(fd uintptr) {
|
||||||
|
syscallErr = syscall.SetsockoptInt(
|
||||||
|
int(fd), syscall.IPPROTO_TCP, tcpUserTimeoutOp, tcpUserTimeoutMilliseconds)
|
||||||
|
})
|
||||||
|
if syscallErr != nil {
|
||||||
|
return syscallErr
|
||||||
|
}
|
||||||
|
if controlErr != nil {
|
||||||
|
return controlErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d := &net.Dialer{
|
||||||
|
Control: control,
|
||||||
|
}
|
||||||
|
return d.DialContext(ctx, "tcp", addr)
|
||||||
|
}
|
||||||
177
vendor/cloud.google.com/go/auth/grpctransport/directpath.go
generated
vendored
Normal file
177
vendor/cloud.google.com/go/auth/grpctransport/directpath.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// Copyright 2023 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 grpctransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials"
|
||||||
|
"cloud.google.com/go/auth/internal/compute"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
grpcgoogle "google.golang.org/grpc/credentials/google"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logRateLimiter = rate.Sometimes{Interval: 1 * time.Second}
|
||||||
|
|
||||||
|
func isDirectPathEnabled(endpoint string, opts *Options) bool {
|
||||||
|
if opts.InternalOptions != nil && !opts.InternalOptions.EnableDirectPath {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !checkDirectPathEndPoint(endpoint) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if b, _ := strconv.ParseBool(os.Getenv(disableDirectPathEnvVar)); b {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkDirectPathEndPoint(endpoint string) bool {
|
||||||
|
// Only [dns:///]host[:port] is supported, not other schemes (e.g., "tcp://" or "unix://").
|
||||||
|
// Also don't try direct path if the user has chosen an alternate name resolver
|
||||||
|
// (i.e., via ":///" prefix).
|
||||||
|
if strings.Contains(endpoint, "://") && !strings.HasPrefix(endpoint, "dns:///") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTokenProviderComputeEngine(tp auth.TokenProvider) bool {
|
||||||
|
if tp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tok, err := tp.Token(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tok == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tok.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tok.MetadataString("auth.google.serviceAccount") != "default" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, o *Options) bool {
|
||||||
|
if tp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if o.InternalOptions != nil && o.InternalOptions.EnableNonDefaultSAForDirectPath {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isTokenProviderComputeEngine(tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDirectPathXdsUsed(o *Options) bool {
|
||||||
|
// Method 1: Enable DirectPath xDS by env;
|
||||||
|
if b, _ := strconv.ParseBool(os.Getenv(enableDirectPathXdsEnvVar)); b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Method 2: Enable DirectPath xDS by option;
|
||||||
|
if o.InternalOptions != nil && o.InternalOptions.EnableDirectPathXds {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDirectPathBoundTokenEnabled(opts *InternalOptions) bool {
|
||||||
|
for _, ev := range opts.AllowHardBoundTokens {
|
||||||
|
if ev == "ALTS" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// configureDirectPath returns some dial options and an endpoint to use if the
|
||||||
|
// configuration allows the use of direct path. If it does not the provided
|
||||||
|
// grpcOpts and endpoint are returned.
|
||||||
|
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *auth.Credentials) ([]grpc.DialOption, string, error) {
|
||||||
|
logRateLimiter.Do(func() {
|
||||||
|
logDirectPathMisconfig(endpoint, creds, opts)
|
||||||
|
})
|
||||||
|
if isDirectPathEnabled(endpoint, opts) && compute.OnComputeEngine() && isTokenProviderDirectPathCompatible(creds, opts) {
|
||||||
|
// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
|
||||||
|
defaultCredetialsOptions := grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcCredentialsProvider{creds: creds}}
|
||||||
|
if isDirectPathBoundTokenEnabled(opts.InternalOptions) && isTokenProviderComputeEngine(creds) {
|
||||||
|
optsClone := opts.resolveDetectOptions()
|
||||||
|
optsClone.TokenBindingType = credentials.ALTSHardBinding
|
||||||
|
altsCreds, err := credentials.DetectDefault(optsClone)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
defaultCredetialsOptions.ALTSPerRPCCreds = &grpcCredentialsProvider{creds: altsCreds}
|
||||||
|
}
|
||||||
|
grpcOpts = []grpc.DialOption{
|
||||||
|
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(defaultCredetialsOptions))}
|
||||||
|
if timeoutDialerOption != nil {
|
||||||
|
grpcOpts = append(grpcOpts, timeoutDialerOption)
|
||||||
|
}
|
||||||
|
// Check if google-c2p resolver is enabled for DirectPath
|
||||||
|
if isDirectPathXdsUsed(opts) {
|
||||||
|
// google-c2p resolver target must not have a port number
|
||||||
|
if addr, _, err := net.SplitHostPort(endpoint); err == nil {
|
||||||
|
endpoint = "google-c2p:///" + addr
|
||||||
|
} else {
|
||||||
|
endpoint = "google-c2p:///" + endpoint
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !strings.HasPrefix(endpoint, "dns:///") {
|
||||||
|
endpoint = "dns:///" + endpoint
|
||||||
|
}
|
||||||
|
grpcOpts = append(grpcOpts,
|
||||||
|
// For now all DirectPath go clients will be using the following lb config, but in future
|
||||||
|
// when different services need different configs, then we should change this to a
|
||||||
|
// per-service config.
|
||||||
|
grpc.WithDisableServiceConfig(),
|
||||||
|
grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"grpclb":{"childPolicy":[{"pick_first":{}}]}}]}`))
|
||||||
|
}
|
||||||
|
// TODO: add support for system parameters (quota project, request reason) via chained interceptor.
|
||||||
|
}
|
||||||
|
return grpcOpts, endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func logDirectPathMisconfig(endpoint string, creds *auth.Credentials, o *Options) {
|
||||||
|
|
||||||
|
// Case 1: does not enable DirectPath
|
||||||
|
if !isDirectPathEnabled(endpoint, o) {
|
||||||
|
o.logger().Warn("DirectPath is disabled. To enable, please set the EnableDirectPath option along with the EnableDirectPathXds option.")
|
||||||
|
} else {
|
||||||
|
// Case 2: credential is not correctly set
|
||||||
|
if !isTokenProviderDirectPathCompatible(creds, o) {
|
||||||
|
o.logger().Warn("DirectPath is disabled. Please make sure the token source is fetched from GCE metadata server and the default service account is used.")
|
||||||
|
}
|
||||||
|
// Case 3: not running on GCE
|
||||||
|
if !compute.OnComputeEngine() {
|
||||||
|
o.logger().Warn("DirectPath is disabled. DirectPath is only available in a GCE environment.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
434
vendor/cloud.google.com/go/auth/grpctransport/grpctransport.go
generated
vendored
Normal file
434
vendor/cloud.google.com/go/auth/grpctransport/grpctransport.go
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
// Copyright 2023 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 grpctransport provides functionality for managing gRPC client
|
||||||
|
// connections to Google Cloud services.
|
||||||
|
package grpctransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/transport"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/headers"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
grpccreds "google.golang.org/grpc/credentials"
|
||||||
|
grpcinsecure "google.golang.org/grpc/credentials/insecure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Check env to disable DirectPath traffic.
|
||||||
|
disableDirectPathEnvVar = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"
|
||||||
|
|
||||||
|
// Check env to decide if using google-c2p resolver for DirectPath traffic.
|
||||||
|
enableDirectPathXdsEnvVar = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"
|
||||||
|
|
||||||
|
quotaProjectHeaderKey = "X-goog-user-project"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Set at init time by dial_socketopt.go. If nil, socketopt is not supported.
|
||||||
|
timeoutDialerOption grpc.DialOption
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientCertProvider is a function that returns a TLS client certificate to be
|
||||||
|
// used when opening TLS connections. It follows the same semantics as
|
||||||
|
// [crypto/tls.Config.GetClientCertificate].
|
||||||
|
type ClientCertProvider = func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
||||||
|
|
||||||
|
// Options used to configure a [GRPCClientConnPool] from [Dial].
|
||||||
|
type Options struct {
|
||||||
|
// DisableTelemetry disables default telemetry (OpenTelemetry). An example
|
||||||
|
// reason to do so would be to bind custom telemetry that overrides the
|
||||||
|
// defaults.
|
||||||
|
DisableTelemetry bool
|
||||||
|
// DisableAuthentication specifies that no authentication should be used. It
|
||||||
|
// is suitable only for testing and for accessing public resources, like
|
||||||
|
// public Google Cloud Storage buckets.
|
||||||
|
DisableAuthentication bool
|
||||||
|
// Endpoint overrides the default endpoint to be used for a service.
|
||||||
|
Endpoint string
|
||||||
|
// Metadata is extra gRPC metadata that will be appended to every outgoing
|
||||||
|
// request.
|
||||||
|
Metadata map[string]string
|
||||||
|
// GRPCDialOpts are dial options that will be passed to `grpc.Dial` when
|
||||||
|
// establishing a`grpc.Conn``
|
||||||
|
GRPCDialOpts []grpc.DialOption
|
||||||
|
// PoolSize is specifies how many connections to balance between when making
|
||||||
|
// requests. If unset or less than 1, the value defaults to 1.
|
||||||
|
PoolSize int
|
||||||
|
// Credentials used to add Authorization metadata to all requests. If set
|
||||||
|
// DetectOpts are ignored.
|
||||||
|
Credentials *auth.Credentials
|
||||||
|
// ClientCertProvider is a function that returns a TLS client certificate to
|
||||||
|
// be used when opening TLS connections. It follows the same semantics as
|
||||||
|
// crypto/tls.Config.GetClientCertificate.
|
||||||
|
ClientCertProvider ClientCertProvider
|
||||||
|
// DetectOpts configures settings for detect Application Default
|
||||||
|
// Credentials.
|
||||||
|
DetectOpts *credentials.DetectOptions
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
// The default value is "googleapis.com". This is the universe domain
|
||||||
|
// configured for the client, which will be compared to the universe domain
|
||||||
|
// that is separately configured for the credentials.
|
||||||
|
UniverseDomain string
|
||||||
|
// APIKey specifies an API key to be used as the basis for authentication.
|
||||||
|
// If set DetectOpts are ignored.
|
||||||
|
APIKey string
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
|
||||||
|
// InternalOptions are NOT meant to be set directly by consumers of this
|
||||||
|
// package, they should only be set by generated client code.
|
||||||
|
InternalOptions *InternalOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// client returns the client a user set for the detect options or nil if one was
|
||||||
|
// not set.
|
||||||
|
func (o *Options) client() *http.Client {
|
||||||
|
if o.DetectOpts != nil && o.DetectOpts.Client != nil {
|
||||||
|
return o.DetectOpts.Client
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) logger() *slog.Logger {
|
||||||
|
return internallog.New(o.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) validate() error {
|
||||||
|
if o == nil {
|
||||||
|
return errors.New("grpctransport: opts required to be non-nil")
|
||||||
|
}
|
||||||
|
if o.InternalOptions != nil && o.InternalOptions.SkipValidation {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hasCreds := o.APIKey != "" ||
|
||||||
|
o.Credentials != nil ||
|
||||||
|
(o.DetectOpts != nil && len(o.DetectOpts.CredentialsJSON) > 0) ||
|
||||||
|
(o.DetectOpts != nil && o.DetectOpts.CredentialsFile != "")
|
||||||
|
if o.DisableAuthentication && hasCreds {
|
||||||
|
return errors.New("grpctransport: DisableAuthentication is incompatible with options that set or detect credentials")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) resolveDetectOptions() *credentials.DetectOptions {
|
||||||
|
io := o.InternalOptions
|
||||||
|
// soft-clone these so we are not updating a ref the user holds and may reuse
|
||||||
|
do := transport.CloneDetectOptions(o.DetectOpts)
|
||||||
|
|
||||||
|
// If scoped JWTs are enabled user provided an aud, allow self-signed JWT.
|
||||||
|
if (io != nil && io.EnableJWTWithScope) || do.Audience != "" {
|
||||||
|
do.UseSelfSignedJWT = true
|
||||||
|
}
|
||||||
|
// Only default scopes if user did not also set an audience.
|
||||||
|
if len(do.Scopes) == 0 && do.Audience == "" && io != nil && len(io.DefaultScopes) > 0 {
|
||||||
|
do.Scopes = make([]string, len(io.DefaultScopes))
|
||||||
|
copy(do.Scopes, io.DefaultScopes)
|
||||||
|
}
|
||||||
|
if len(do.Scopes) == 0 && do.Audience == "" && io != nil {
|
||||||
|
do.Audience = o.InternalOptions.DefaultAudience
|
||||||
|
}
|
||||||
|
if o.ClientCertProvider != nil {
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
GetClientCertificate: o.ClientCertProvider,
|
||||||
|
}
|
||||||
|
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
|
||||||
|
do.TokenURL = credentials.GoogleMTLSTokenURL
|
||||||
|
}
|
||||||
|
if do.Logger == nil {
|
||||||
|
do.Logger = o.logger()
|
||||||
|
}
|
||||||
|
return do
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalOptions are only meant to be set by generated client code. These are
|
||||||
|
// not meant to be set directly by consumers of this package. Configuration in
|
||||||
|
// this type is considered EXPERIMENTAL and may be removed at any time in the
|
||||||
|
// future without warning.
|
||||||
|
type InternalOptions struct {
|
||||||
|
// EnableNonDefaultSAForDirectPath overrides the default requirement for
|
||||||
|
// using the default service account for DirectPath.
|
||||||
|
EnableNonDefaultSAForDirectPath bool
|
||||||
|
// EnableDirectPath overrides the default attempt to use DirectPath.
|
||||||
|
EnableDirectPath bool
|
||||||
|
// EnableDirectPathXds overrides the default DirectPath type. It is only
|
||||||
|
// valid when DirectPath is enabled.
|
||||||
|
EnableDirectPathXds bool
|
||||||
|
// EnableJWTWithScope specifies if scope can be used with self-signed JWT.
|
||||||
|
EnableJWTWithScope bool
|
||||||
|
// AllowHardBoundTokens allows libraries to request a hard-bound token.
|
||||||
|
// Obtaining hard-bound tokens requires the connection to be established
|
||||||
|
// using either ALTS or mTLS with S2A.
|
||||||
|
AllowHardBoundTokens []string
|
||||||
|
// DefaultAudience specifies a default audience to be used as the audience
|
||||||
|
// field ("aud") for the JWT token authentication.
|
||||||
|
DefaultAudience string
|
||||||
|
// DefaultEndpointTemplate combined with UniverseDomain specifies
|
||||||
|
// the default endpoint.
|
||||||
|
DefaultEndpointTemplate string
|
||||||
|
// DefaultMTLSEndpoint specifies the default mTLS endpoint.
|
||||||
|
DefaultMTLSEndpoint string
|
||||||
|
// DefaultScopes specifies the default OAuth2 scopes to be used for a
|
||||||
|
// service.
|
||||||
|
DefaultScopes []string
|
||||||
|
// SkipValidation bypasses validation on Options. It should only be used
|
||||||
|
// internally for clients that needs more control over their transport.
|
||||||
|
SkipValidation bool
|
||||||
|
// TelemetryAttributes specifies a map of telemetry attributes to be added
|
||||||
|
// to all OpenTelemetry signals, such as tracing and metrics, for purposes
|
||||||
|
// including representing the static identity of the client (e.g., service
|
||||||
|
// name, version). These attributes are expected to be consistent across all
|
||||||
|
// signals to enable cross-signal correlation.
|
||||||
|
//
|
||||||
|
// It should only be used internally by generated clients. Callers should not
|
||||||
|
// modify the map after it is passed in.
|
||||||
|
TelemetryAttributes map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial returns a GRPCClientConnPool that can be used to communicate with a
|
||||||
|
// Google cloud service, configured with the provided [Options]. It
|
||||||
|
// automatically appends Authorization metadata to all outgoing requests.
|
||||||
|
func Dial(ctx context.Context, secure bool, opts *Options) (GRPCClientConnPool, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if opts.PoolSize <= 1 {
|
||||||
|
conn, err := dial(ctx, secure, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &singleConnPool{conn}, nil
|
||||||
|
}
|
||||||
|
pool := &roundRobinConnPool{}
|
||||||
|
for i := 0; i < opts.PoolSize; i++ {
|
||||||
|
conn, err := dial(ctx, secure, opts)
|
||||||
|
if err != nil {
|
||||||
|
// ignore close error, if any
|
||||||
|
defer pool.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pool.conns = append(pool.conns, conn)
|
||||||
|
}
|
||||||
|
return pool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a GRPCClientConnPool if pool == 1 or else a pool of of them if >1
|
||||||
|
func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, error) {
|
||||||
|
tOpts := &transport.Options{
|
||||||
|
Endpoint: opts.Endpoint,
|
||||||
|
ClientCertProvider: opts.ClientCertProvider,
|
||||||
|
Client: opts.client(),
|
||||||
|
UniverseDomain: opts.UniverseDomain,
|
||||||
|
Logger: opts.logger(),
|
||||||
|
}
|
||||||
|
if io := opts.InternalOptions; io != nil {
|
||||||
|
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
|
||||||
|
tOpts.DefaultMTLSEndpoint = io.DefaultMTLSEndpoint
|
||||||
|
tOpts.EnableDirectPath = io.EnableDirectPath
|
||||||
|
tOpts.EnableDirectPathXds = io.EnableDirectPathXds
|
||||||
|
}
|
||||||
|
transportCreds, err := transport.GetGRPCTransportCredsAndEndpoint(tOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !secure {
|
||||||
|
transportCreds.TransportCredentials = grpcinsecure.NewCredentials()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize gRPC dial options with transport-level security options.
|
||||||
|
grpcOpts := []grpc.DialOption{
|
||||||
|
grpc.WithTransportCredentials(transportCreds),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the token exchange HTTP transport uses the same ClientCertProvider as the GRPC API transport.
|
||||||
|
opts.ClientCertProvider, err = transport.GetClientCertificateProvider(tOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.APIKey != "" {
|
||||||
|
grpcOpts = append(grpcOpts,
|
||||||
|
grpc.WithPerRPCCredentials(&grpcKeyProvider{
|
||||||
|
apiKey: opts.APIKey,
|
||||||
|
metadata: opts.Metadata,
|
||||||
|
secure: secure,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else if !opts.DisableAuthentication {
|
||||||
|
metadata := opts.Metadata
|
||||||
|
|
||||||
|
var creds *auth.Credentials
|
||||||
|
if opts.Credentials != nil {
|
||||||
|
creds = opts.Credentials
|
||||||
|
} else {
|
||||||
|
// This condition is only met for non-DirectPath clients because
|
||||||
|
// TransportTypeMTLSS2A is used only when InternalOptions.EnableDirectPath
|
||||||
|
// is false.
|
||||||
|
optsClone := opts.resolveDetectOptions()
|
||||||
|
if transportCreds.TransportType == transport.TransportTypeMTLSS2A {
|
||||||
|
// Check that the client allows requesting hard-bound token for the transport type mTLS using S2A.
|
||||||
|
for _, ev := range opts.InternalOptions.AllowHardBoundTokens {
|
||||||
|
if ev == "MTLS_S2A" {
|
||||||
|
optsClone.TokenBindingType = credentials.MTLSHardBinding
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
creds, err = credentials.DetectDefault(optsClone)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qp, err := creds.QuotaProjectID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if qp != "" {
|
||||||
|
if metadata == nil {
|
||||||
|
metadata = make(map[string]string, 1)
|
||||||
|
}
|
||||||
|
// Don't overwrite user specified quota
|
||||||
|
if _, ok := metadata[quotaProjectHeaderKey]; !ok {
|
||||||
|
metadata[quotaProjectHeaderKey] = qp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grpcOpts = append(grpcOpts,
|
||||||
|
grpc.WithPerRPCCredentials(&grpcCredentialsProvider{
|
||||||
|
creds: creds,
|
||||||
|
metadata: metadata,
|
||||||
|
clientUniverseDomain: opts.UniverseDomain,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
// Attempt Direct Path
|
||||||
|
grpcOpts, transportCreds.Endpoint, err = configureDirectPath(grpcOpts, opts, transportCreds.Endpoint, creds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tracing, but before the other options, so that clients can override the
|
||||||
|
// gRPC stats handler.
|
||||||
|
// This assumes that gRPC options are processed in order, left to right.
|
||||||
|
grpcOpts = addOpenTelemetryStatsHandler(grpcOpts, opts)
|
||||||
|
grpcOpts = append(grpcOpts, opts.GRPCDialOpts...)
|
||||||
|
|
||||||
|
return grpc.DialContext(ctx, transportCreds.Endpoint, grpcOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// grpcKeyProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
|
||||||
|
type grpcKeyProvider struct {
|
||||||
|
apiKey string
|
||||||
|
metadata map[string]string
|
||||||
|
secure bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcKeyProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
|
metadata := make(map[string]string, len(g.metadata)+1)
|
||||||
|
metadata["X-goog-api-key"] = g.apiKey
|
||||||
|
for k, v := range g.metadata {
|
||||||
|
metadata[k] = v
|
||||||
|
}
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcKeyProvider) RequireTransportSecurity() bool {
|
||||||
|
return g.secure
|
||||||
|
}
|
||||||
|
|
||||||
|
// grpcCredentialsProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
|
||||||
|
type grpcCredentialsProvider struct {
|
||||||
|
creds *auth.Credentials
|
||||||
|
|
||||||
|
secure bool
|
||||||
|
|
||||||
|
// Additional metadata attached as headers.
|
||||||
|
metadata map[string]string
|
||||||
|
clientUniverseDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClientUniverseDomain returns the default service domain for a given Cloud
|
||||||
|
// universe, with the following precedence:
|
||||||
|
//
|
||||||
|
// 1. A non-empty option.WithUniverseDomain or similar client option.
|
||||||
|
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
|
||||||
|
// 3. The default value "googleapis.com".
|
||||||
|
//
|
||||||
|
// This is the universe domain configured for the client, which will be compared
|
||||||
|
// to the universe domain that is separately configured for the credentials.
|
||||||
|
func (c *grpcCredentialsProvider) getClientUniverseDomain() string {
|
||||||
|
if c.clientUniverseDomain != "" {
|
||||||
|
return c.clientUniverseDomain
|
||||||
|
}
|
||||||
|
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
|
||||||
|
return envUD
|
||||||
|
}
|
||||||
|
return internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
|
token, err := c.creds.Token(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
|
credentialsUniverseDomain, err := c.creds.UniverseDomain(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := transport.ValidateUniverseDomain(c.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.secure {
|
||||||
|
ri, _ := grpccreds.RequestInfoFromContext(ctx)
|
||||||
|
if err = grpccreds.CheckSecurityLevel(ri.AuthInfo, grpccreds.PrivacyAndIntegrity); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to transfer credentials PerRPCCredentials: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metadata := make(map[string]string, len(c.metadata)+1)
|
||||||
|
headers.SetAuthMetadata(token, metadata)
|
||||||
|
for k, v := range c.metadata {
|
||||||
|
metadata[k] = v
|
||||||
|
}
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *grpcCredentialsProvider) RequireTransportSecurity() bool {
|
||||||
|
return c.secure
|
||||||
|
}
|
||||||
|
|
||||||
|
func addOpenTelemetryStatsHandler(dialOpts []grpc.DialOption, opts *Options) []grpc.DialOption {
|
||||||
|
if opts.DisableTelemetry {
|
||||||
|
return dialOpts
|
||||||
|
}
|
||||||
|
return append(dialOpts, grpc.WithStatsHandler(otelgrpc.NewClientHandler()))
|
||||||
|
}
|
||||||
119
vendor/cloud.google.com/go/auth/grpctransport/pool.go
generated
vendored
Normal file
119
vendor/cloud.google.com/go/auth/grpctransport/pool.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright 2023 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 grpctransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GRPCClientConnPool is an interface that satisfies
|
||||||
|
// [google.golang.org/grpc.ClientConnInterface] and has some utility functions
|
||||||
|
// that are needed for connection lifecycle when using in a client library. It
|
||||||
|
// may be a pool or a single connection. This interface is not intended to, and
|
||||||
|
// can't be, implemented by others.
|
||||||
|
type GRPCClientConnPool interface {
|
||||||
|
// Connection returns a [google.golang.org/grpc.ClientConn] from the pool.
|
||||||
|
//
|
||||||
|
// ClientConn aren't returned to the pool and should not be closed directly.
|
||||||
|
Connection() *grpc.ClientConn
|
||||||
|
|
||||||
|
// Len returns the number of connections in the pool. It will always return
|
||||||
|
// the same value.
|
||||||
|
Len() int
|
||||||
|
|
||||||
|
// Close closes every ClientConn in the pool. The error returned by Close
|
||||||
|
// may be a single error or multiple errors.
|
||||||
|
Close() error
|
||||||
|
|
||||||
|
grpc.ClientConnInterface
|
||||||
|
|
||||||
|
// private ensure others outside this package can't implement this type
|
||||||
|
private()
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleConnPool is a special case for a single connection.
|
||||||
|
type singleConnPool struct {
|
||||||
|
*grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *singleConnPool) Connection() *grpc.ClientConn { return p.ClientConn }
|
||||||
|
func (p *singleConnPool) Len() int { return 1 }
|
||||||
|
func (p *singleConnPool) private() {}
|
||||||
|
|
||||||
|
type roundRobinConnPool struct {
|
||||||
|
conns []*grpc.ClientConn
|
||||||
|
|
||||||
|
idx uint32 // access via sync/atomic
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) Len() int {
|
||||||
|
return len(p.conns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) Connection() *grpc.ClientConn {
|
||||||
|
i := atomic.AddUint32(&p.idx, 1)
|
||||||
|
return p.conns[i%uint32(len(p.conns))]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) Close() error {
|
||||||
|
var errs multiError
|
||||||
|
for _, conn := range p.conns {
|
||||||
|
if err := conn.Close(); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error {
|
||||||
|
return p.Connection().Invoke(ctx, method, args, reply, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||||
|
return p.Connection().NewStream(ctx, desc, method, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *roundRobinConnPool) private() {}
|
||||||
|
|
||||||
|
// multiError represents errors from multiple conns in the group.
|
||||||
|
type multiError []error
|
||||||
|
|
||||||
|
func (m multiError) Error() string {
|
||||||
|
s, n := "", 0
|
||||||
|
for _, e := range m {
|
||||||
|
if e != nil {
|
||||||
|
if n == 0 {
|
||||||
|
s = e.Error()
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
return "(0 errors)"
|
||||||
|
case 1:
|
||||||
|
return s
|
||||||
|
case 2:
|
||||||
|
return s + " (and 1 other error)"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (and %d other errors)", s, n-1)
|
||||||
|
}
|
||||||
254
vendor/cloud.google.com/go/auth/httptransport/httptransport.go
generated
vendored
Normal file
254
vendor/cloud.google.com/go/auth/httptransport/httptransport.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
// Copyright 2023 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 httptransport provides functionality for managing HTTP client
|
||||||
|
// connections to Google Cloud services.
|
||||||
|
package httptransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
detect "cloud.google.com/go/auth/credentials"
|
||||||
|
"cloud.google.com/go/auth/internal/transport"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/headers"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientCertProvider is a function that returns a TLS client certificate to be
|
||||||
|
// used when opening TLS connections. It follows the same semantics as
|
||||||
|
// [crypto/tls.Config.GetClientCertificate].
|
||||||
|
type ClientCertProvider = func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
||||||
|
|
||||||
|
// Options used to configure a [net/http.Client] from [NewClient].
|
||||||
|
type Options struct {
|
||||||
|
// DisableTelemetry disables default telemetry (OpenTelemetry). An example
|
||||||
|
// reason to do so would be to bind custom telemetry that overrides the
|
||||||
|
// defaults.
|
||||||
|
DisableTelemetry bool
|
||||||
|
// DisableAuthentication specifies that no authentication should be used. It
|
||||||
|
// is suitable only for testing and for accessing public resources, like
|
||||||
|
// public Google Cloud Storage buckets.
|
||||||
|
DisableAuthentication bool
|
||||||
|
// Headers are extra HTTP headers that will be appended to every outgoing
|
||||||
|
// request.
|
||||||
|
Headers http.Header
|
||||||
|
// BaseRoundTripper overrides the base transport used for serving requests.
|
||||||
|
// If specified ClientCertProvider is ignored.
|
||||||
|
BaseRoundTripper http.RoundTripper
|
||||||
|
// Endpoint overrides the default endpoint to be used for a service.
|
||||||
|
Endpoint string
|
||||||
|
// APIKey specifies an API key to be used as the basis for authentication.
|
||||||
|
// If set DetectOpts are ignored.
|
||||||
|
APIKey string
|
||||||
|
// Credentials used to add Authorization header to all requests. If set
|
||||||
|
// DetectOpts are ignored.
|
||||||
|
Credentials *auth.Credentials
|
||||||
|
// ClientCertProvider is a function that returns a TLS client certificate to
|
||||||
|
// be used when opening TLS connections. It follows the same semantics as
|
||||||
|
// crypto/tls.Config.GetClientCertificate.
|
||||||
|
ClientCertProvider ClientCertProvider
|
||||||
|
// DetectOpts configures settings for detect Application Default
|
||||||
|
// Credentials.
|
||||||
|
DetectOpts *detect.DetectOptions
|
||||||
|
// UniverseDomain is the default service domain for a given Cloud universe.
|
||||||
|
// The default value is "googleapis.com". This is the universe domain
|
||||||
|
// configured for the client, which will be compared to the universe domain
|
||||||
|
// that is separately configured for the credentials.
|
||||||
|
UniverseDomain string
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
|
||||||
|
// InternalOptions are NOT meant to be set directly by consumers of this
|
||||||
|
// package, they should only be set by generated client code.
|
||||||
|
InternalOptions *InternalOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) validate() error {
|
||||||
|
if o == nil {
|
||||||
|
return errors.New("httptransport: opts required to be non-nil")
|
||||||
|
}
|
||||||
|
if o.InternalOptions != nil && o.InternalOptions.SkipValidation {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hasCreds := o.APIKey != "" ||
|
||||||
|
o.Credentials != nil ||
|
||||||
|
(o.DetectOpts != nil && len(o.DetectOpts.CredentialsJSON) > 0) ||
|
||||||
|
(o.DetectOpts != nil && o.DetectOpts.CredentialsFile != "")
|
||||||
|
if o.DisableAuthentication && hasCreds {
|
||||||
|
return errors.New("httptransport: DisableAuthentication is incompatible with options that set or detect credentials")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// client returns the client a user set for the detect options or nil if one was
|
||||||
|
// not set.
|
||||||
|
func (o *Options) client() *http.Client {
|
||||||
|
if o.DetectOpts != nil && o.DetectOpts.Client != nil {
|
||||||
|
return o.DetectOpts.Client
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) logger() *slog.Logger {
|
||||||
|
return internallog.New(o.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) resolveDetectOptions() *detect.DetectOptions {
|
||||||
|
io := o.InternalOptions
|
||||||
|
// soft-clone these so we are not updating a ref the user holds and may reuse
|
||||||
|
do := transport.CloneDetectOptions(o.DetectOpts)
|
||||||
|
|
||||||
|
// If scoped JWTs are enabled user provided an aud, allow self-signed JWT.
|
||||||
|
if (io != nil && io.EnableJWTWithScope) || do.Audience != "" {
|
||||||
|
do.UseSelfSignedJWT = true
|
||||||
|
}
|
||||||
|
// Only default scopes if user did not also set an audience.
|
||||||
|
if len(do.Scopes) == 0 && do.Audience == "" && io != nil && len(io.DefaultScopes) > 0 {
|
||||||
|
do.Scopes = make([]string, len(io.DefaultScopes))
|
||||||
|
copy(do.Scopes, io.DefaultScopes)
|
||||||
|
}
|
||||||
|
if len(do.Scopes) == 0 && do.Audience == "" && io != nil {
|
||||||
|
do.Audience = o.InternalOptions.DefaultAudience
|
||||||
|
}
|
||||||
|
if o.ClientCertProvider != nil {
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
GetClientCertificate: o.ClientCertProvider,
|
||||||
|
}
|
||||||
|
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
|
||||||
|
do.TokenURL = detect.GoogleMTLSTokenURL
|
||||||
|
}
|
||||||
|
if do.Logger == nil {
|
||||||
|
do.Logger = o.logger()
|
||||||
|
}
|
||||||
|
return do
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalOptions are only meant to be set by generated client code. These are
|
||||||
|
// not meant to be set directly by consumers of this package. Configuration in
|
||||||
|
// this type is considered EXPERIMENTAL and may be removed at any time in the
|
||||||
|
// future without warning.
|
||||||
|
type InternalOptions struct {
|
||||||
|
// EnableJWTWithScope specifies if scope can be used with self-signed JWT.
|
||||||
|
EnableJWTWithScope bool
|
||||||
|
// DefaultAudience specifies a default audience to be used as the audience
|
||||||
|
// field ("aud") for the JWT token authentication.
|
||||||
|
DefaultAudience string
|
||||||
|
// DefaultEndpointTemplate combined with UniverseDomain specifies the
|
||||||
|
// default endpoint.
|
||||||
|
DefaultEndpointTemplate string
|
||||||
|
// DefaultMTLSEndpoint specifies the default mTLS endpoint.
|
||||||
|
DefaultMTLSEndpoint string
|
||||||
|
// DefaultScopes specifies the default OAuth2 scopes to be used for a
|
||||||
|
// service.
|
||||||
|
DefaultScopes []string
|
||||||
|
// SkipValidation bypasses validation on Options. It should only be used
|
||||||
|
// internally for clients that need more control over their transport.
|
||||||
|
SkipValidation bool
|
||||||
|
// SkipUniverseDomainValidation skips the verification that the universe
|
||||||
|
// domain configured for the client matches the universe domain configured
|
||||||
|
// for the credentials. It should only be used internally for clients that
|
||||||
|
// need more control over their transport. The default is false.
|
||||||
|
SkipUniverseDomainValidation bool
|
||||||
|
// TelemetryAttributes specifies a map of telemetry attributes to be added
|
||||||
|
// to all OpenTelemetry signals, such as tracing and metrics, for purposes
|
||||||
|
// including representing the static identity of the client (e.g., service
|
||||||
|
// name, version). These attributes are expected to be consistent across all
|
||||||
|
// signals to enable cross-signal correlation.
|
||||||
|
//
|
||||||
|
// It should only be used internally by generated clients. Callers should not
|
||||||
|
// modify the map after it is passed in.
|
||||||
|
TelemetryAttributes map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAuthorizationMiddleware adds a middleware to the provided client's
|
||||||
|
// transport that sets the Authorization header with the value produced by the
|
||||||
|
// provided [cloud.google.com/go/auth.Credentials]. An error is returned only
|
||||||
|
// if client or creds is nil.
|
||||||
|
//
|
||||||
|
// This function does not support setting a universe domain value on the client.
|
||||||
|
func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) error {
|
||||||
|
if client == nil || creds == nil {
|
||||||
|
return fmt.Errorf("httptransport: client and tp must not be nil")
|
||||||
|
}
|
||||||
|
base := client.Transport
|
||||||
|
if base == nil {
|
||||||
|
if dt, ok := http.DefaultTransport.(*http.Transport); ok {
|
||||||
|
base = dt.Clone()
|
||||||
|
} else {
|
||||||
|
// Directly reuse the DefaultTransport if the application has
|
||||||
|
// replaced it with an implementation of RoundTripper other than
|
||||||
|
// http.Transport.
|
||||||
|
base = http.DefaultTransport
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.Transport = &authTransport{
|
||||||
|
creds: creds,
|
||||||
|
base: base,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a [net/http.Client] that can be used to communicate with a
|
||||||
|
// Google cloud service, configured with the provided [Options]. It
|
||||||
|
// automatically appends Authorization headers to all outgoing requests.
|
||||||
|
func NewClient(opts *Options) (*http.Client, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tOpts := &transport.Options{
|
||||||
|
Endpoint: opts.Endpoint,
|
||||||
|
ClientCertProvider: opts.ClientCertProvider,
|
||||||
|
Client: opts.client(),
|
||||||
|
UniverseDomain: opts.UniverseDomain,
|
||||||
|
Logger: opts.logger(),
|
||||||
|
}
|
||||||
|
if io := opts.InternalOptions; io != nil {
|
||||||
|
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
|
||||||
|
tOpts.DefaultMTLSEndpoint = io.DefaultMTLSEndpoint
|
||||||
|
}
|
||||||
|
clientCertProvider, dialTLSContext, err := transport.GetHTTPTransportConfig(tOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseRoundTripper := opts.BaseRoundTripper
|
||||||
|
if baseRoundTripper == nil {
|
||||||
|
baseRoundTripper = defaultBaseTransport(clientCertProvider, dialTLSContext)
|
||||||
|
}
|
||||||
|
// Ensure the token exchange transport uses the same ClientCertProvider as the API transport.
|
||||||
|
opts.ClientCertProvider = clientCertProvider
|
||||||
|
trans, err := newTransport(baseRoundTripper, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &http.Client{
|
||||||
|
Transport: trans,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthHeader uses the provided token to set the Authorization and trust
|
||||||
|
// boundary headers on an http.Request. If the token.Type is empty, the type is
|
||||||
|
// assumed to be Bearer. This is the recommended way to set authorization
|
||||||
|
// headers on a custom http.Request.
|
||||||
|
func SetAuthHeader(token *auth.Token, req *http.Request) {
|
||||||
|
headers.SetAuthHeader(token, req)
|
||||||
|
}
|
||||||
235
vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
Normal file
235
vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
// Copyright 2023 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 httptransport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/credentials"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/transport"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/cert"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/headers"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
quotaProjectHeaderKey = "X-goog-user-project"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, error) {
|
||||||
|
var headers = opts.Headers
|
||||||
|
ht := &headerTransport{
|
||||||
|
base: base,
|
||||||
|
headers: headers,
|
||||||
|
}
|
||||||
|
var trans http.RoundTripper = ht
|
||||||
|
trans = addOpenTelemetryTransport(trans, opts)
|
||||||
|
switch {
|
||||||
|
case opts.DisableAuthentication:
|
||||||
|
// Do nothing.
|
||||||
|
case opts.APIKey != "":
|
||||||
|
qp := internal.GetQuotaProject(nil, opts.Headers.Get(quotaProjectHeaderKey))
|
||||||
|
if qp != "" {
|
||||||
|
if headers == nil {
|
||||||
|
headers = make(map[string][]string, 1)
|
||||||
|
}
|
||||||
|
headers.Set(quotaProjectHeaderKey, qp)
|
||||||
|
}
|
||||||
|
trans = &apiKeyTransport{
|
||||||
|
Transport: trans,
|
||||||
|
Key: opts.APIKey,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
var creds *auth.Credentials
|
||||||
|
if opts.Credentials != nil {
|
||||||
|
creds = opts.Credentials
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
creds, err = credentials.DetectDefault(opts.resolveDetectOptions())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qp, err := creds.QuotaProjectID(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if qp != "" {
|
||||||
|
if headers == nil {
|
||||||
|
headers = make(map[string][]string, 1)
|
||||||
|
}
|
||||||
|
// Don't overwrite user specified quota
|
||||||
|
if v := headers.Get(quotaProjectHeaderKey); v == "" {
|
||||||
|
headers.Set(quotaProjectHeaderKey, qp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var skipUD bool
|
||||||
|
if iOpts := opts.InternalOptions; iOpts != nil {
|
||||||
|
skipUD = iOpts.SkipUniverseDomainValidation
|
||||||
|
}
|
||||||
|
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
|
||||||
|
trans = &authTransport{
|
||||||
|
base: trans,
|
||||||
|
creds: creds,
|
||||||
|
clientUniverseDomain: opts.UniverseDomain,
|
||||||
|
skipUniverseDomainValidation: skipUD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trans, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultBaseTransport returns the base HTTP transport.
|
||||||
|
// On App Engine, this is urlfetch.Transport.
|
||||||
|
// Otherwise, use a default transport, taking most defaults from
|
||||||
|
// http.DefaultTransport.
|
||||||
|
// If TLSCertificate is available, set TLSClientConfig as well.
|
||||||
|
func defaultBaseTransport(clientCertSource cert.Provider, dialTLSContext func(context.Context, string, string) (net.Conn, error)) http.RoundTripper {
|
||||||
|
defaultTransport, ok := http.DefaultTransport.(*http.Transport)
|
||||||
|
if !ok {
|
||||||
|
defaultTransport = transport.BaseTransport()
|
||||||
|
}
|
||||||
|
trans := defaultTransport.Clone()
|
||||||
|
trans.MaxIdleConnsPerHost = 100
|
||||||
|
|
||||||
|
if clientCertSource != nil {
|
||||||
|
trans.TLSClientConfig = &tls.Config{
|
||||||
|
GetClientCertificate: clientCertSource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dialTLSContext != nil {
|
||||||
|
// If DialTLSContext is set, TLSClientConfig wil be ignored
|
||||||
|
trans.DialTLSContext = dialTLSContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configures the ReadIdleTimeout HTTP/2 option for the
|
||||||
|
// transport. This allows broken idle connections to be pruned more quickly,
|
||||||
|
// preventing the client from attempting to re-use connections that will no
|
||||||
|
// longer work.
|
||||||
|
http2Trans, err := http2.ConfigureTransports(trans)
|
||||||
|
if err == nil {
|
||||||
|
http2Trans.ReadIdleTimeout = time.Second * 31
|
||||||
|
}
|
||||||
|
|
||||||
|
return trans
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiKeyTransport struct {
|
||||||
|
// Key is the API Key to set on requests.
|
||||||
|
Key string
|
||||||
|
// Transport is the underlying HTTP transport.
|
||||||
|
// If nil, http.DefaultTransport is used.
|
||||||
|
Transport http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *apiKeyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
newReq := *req
|
||||||
|
args := newReq.URL.Query()
|
||||||
|
args.Set("key", t.Key)
|
||||||
|
newReq.URL.RawQuery = args.Encode()
|
||||||
|
return t.Transport.RoundTrip(&newReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerTransport struct {
|
||||||
|
headers http.Header
|
||||||
|
base http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
rt := t.base
|
||||||
|
newReq := *req
|
||||||
|
newReq.Header = make(http.Header)
|
||||||
|
for k, vv := range req.Header {
|
||||||
|
newReq.Header[k] = vv
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range t.headers {
|
||||||
|
newReq.Header[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return rt.RoundTrip(&newReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addOpenTelemetryTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
|
||||||
|
if opts.DisableTelemetry {
|
||||||
|
return trans
|
||||||
|
}
|
||||||
|
return otelhttp.NewTransport(trans)
|
||||||
|
}
|
||||||
|
|
||||||
|
type authTransport struct {
|
||||||
|
creds *auth.Credentials
|
||||||
|
base http.RoundTripper
|
||||||
|
clientUniverseDomain string
|
||||||
|
skipUniverseDomainValidation bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClientUniverseDomain returns the default service domain for a given Cloud
|
||||||
|
// universe, with the following precedence:
|
||||||
|
//
|
||||||
|
// 1. A non-empty option.WithUniverseDomain or similar client option.
|
||||||
|
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
|
||||||
|
// 3. The default value "googleapis.com".
|
||||||
|
//
|
||||||
|
// This is the universe domain configured for the client, which will be compared
|
||||||
|
// to the universe domain that is separately configured for the credentials.
|
||||||
|
func (t *authTransport) getClientUniverseDomain() string {
|
||||||
|
if t.clientUniverseDomain != "" {
|
||||||
|
return t.clientUniverseDomain
|
||||||
|
}
|
||||||
|
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
|
||||||
|
return envUD
|
||||||
|
}
|
||||||
|
return internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip authorizes and authenticates the request with an
|
||||||
|
// access token from Transport's Source. Per the RoundTripper contract we must
|
||||||
|
// not modify the initial request, so we clone it, and we must close the body
|
||||||
|
// on any errors that happens during our token logic.
|
||||||
|
func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
reqBodyClosed := false
|
||||||
|
if req.Body != nil {
|
||||||
|
defer func() {
|
||||||
|
if !reqBodyClosed {
|
||||||
|
req.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
token, err := t.creds.Token(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !t.skipUniverseDomainValidation && token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
|
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := transport.ValidateUniverseDomain(t.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req2 := req.Clone(req.Context())
|
||||||
|
headers.SetAuthHeader(token, req2)
|
||||||
|
reqBodyClosed = true
|
||||||
|
return t.base.RoundTrip(req2)
|
||||||
|
}
|
||||||
65
vendor/cloud.google.com/go/auth/internal/compute/compute.go
generated
vendored
Normal file
65
vendor/cloud.google.com/go/auth/internal/compute/compute.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2024 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 compute
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
vmOnGCEOnce sync.Once
|
||||||
|
vmOnGCE bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnComputeEngine returns whether the client is running on GCE.
|
||||||
|
//
|
||||||
|
// This is a copy of the gRPC internal googlecloud.OnGCE() func at:
|
||||||
|
// https://github.com/grpc/grpc-go/blob/master/internal/googlecloud/googlecloud.go
|
||||||
|
// The functionality is similar to the metadata.OnGCE() func at:
|
||||||
|
// https://github.com/googleapis/google-cloud-go/blob/main/compute/metadata/metadata.go
|
||||||
|
// The difference is that OnComputeEngine() does not perform HTTP or DNS check on the metadata server.
|
||||||
|
// In particular, OnComputeEngine() will return false on Serverless.
|
||||||
|
func OnComputeEngine() bool {
|
||||||
|
vmOnGCEOnce.Do(func() {
|
||||||
|
mf, err := manufacturer()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to read manufacturer, vmOnGCE=false: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vmOnGCE = isRunningOnGCE(mf, runtime.GOOS)
|
||||||
|
})
|
||||||
|
return vmOnGCE
|
||||||
|
}
|
||||||
|
|
||||||
|
// isRunningOnGCE checks whether the local system, without doing a network request, is
|
||||||
|
// running on GCP.
|
||||||
|
func isRunningOnGCE(manufacturer []byte, goos string) bool {
|
||||||
|
name := string(manufacturer)
|
||||||
|
switch goos {
|
||||||
|
case "linux":
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
return name == "Google" || name == "Google Compute Engine"
|
||||||
|
case "windows":
|
||||||
|
name = strings.Replace(name, " ", "", -1)
|
||||||
|
name = strings.Replace(name, "\n", "", -1)
|
||||||
|
name = strings.Replace(name, "\r", "", -1)
|
||||||
|
return name == "Google"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
22
vendor/cloud.google.com/go/auth/internal/compute/manufacturer.go
generated
vendored
Normal file
22
vendor/cloud.google.com/go/auth/internal/compute/manufacturer.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//go:build !(linux || windows)
|
||||||
|
// +build !linux,!windows
|
||||||
|
|
||||||
|
// Copyright 2024 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 compute
|
||||||
|
|
||||||
|
func manufacturer() ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
23
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_linux.go
generated
vendored
Normal file
23
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_linux.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2024 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 compute
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
const linuxProductNameFile = "/sys/class/dmi/id/product_name"
|
||||||
|
|
||||||
|
func manufacturer() ([]byte, error) {
|
||||||
|
return os.ReadFile(linuxProductNameFile)
|
||||||
|
}
|
||||||
46
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_windows.go
generated
vendored
Normal file
46
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_windows.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2024 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 compute
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
windowsCheckCommand = "powershell.exe"
|
||||||
|
windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS"
|
||||||
|
powershellOutputFilter = "Manufacturer"
|
||||||
|
windowsManufacturerRegex = ":(.*)"
|
||||||
|
)
|
||||||
|
|
||||||
|
func manufacturer() ([]byte, error) {
|
||||||
|
cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
|
||||||
|
if strings.HasPrefix(line, powershellOutputFilter) {
|
||||||
|
re := regexp.MustCompile(windowsManufacturerRegex)
|
||||||
|
name := re.FindString(line)
|
||||||
|
name = strings.TrimLeft(name, ":")
|
||||||
|
return []byte(name), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("cannot determine the machine's manufacturer")
|
||||||
|
}
|
||||||
63
vendor/cloud.google.com/go/auth/internal/credsfile/credsfile.go
generated
vendored
Normal file
63
vendor/cloud.google.com/go/auth/internal/credsfile/credsfile.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2023 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 credsfile is meant to hide implementation details from the pubic
|
||||||
|
// surface of the detect package. It should not import any other packages in
|
||||||
|
// this module. It is located under the main internal package so other
|
||||||
|
// sub-packages can use these parsed types as well.
|
||||||
|
package credsfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GoogleAppCredsEnvVar is the environment variable for setting the
|
||||||
|
// application default credentials.
|
||||||
|
GoogleAppCredsEnvVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||||
|
userCredsFilename = "application_default_credentials.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFileNameFromEnv returns the override if provided or detects a filename
|
||||||
|
// from the environment.
|
||||||
|
func GetFileNameFromEnv(override string) string {
|
||||||
|
if override != "" {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
return os.Getenv(GoogleAppCredsEnvVar)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWellKnownFileName tries to locate the filepath for the user credential
|
||||||
|
// file based on the environment.
|
||||||
|
func GetWellKnownFileName() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return filepath.Join(os.Getenv("APPDATA"), "gcloud", userCredsFilename)
|
||||||
|
}
|
||||||
|
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", userCredsFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// guessUnixHomeDir default to checking for HOME, but not all unix systems have
|
||||||
|
// this set, do have a fallback.
|
||||||
|
func guessUnixHomeDir() string {
|
||||||
|
if v := os.Getenv("HOME"); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if u, err := user.Current(); err == nil {
|
||||||
|
return u.HomeDir
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
159
vendor/cloud.google.com/go/auth/internal/credsfile/filetype.go
generated
vendored
Normal file
159
vendor/cloud.google.com/go/auth/internal/credsfile/filetype.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// Copyright 2023 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 credsfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config3LO is the internals of a client creds file.
|
||||||
|
type Config3LO struct {
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
RedirectURIs []string `json:"redirect_uris"`
|
||||||
|
AuthURI string `json:"auth_uri"`
|
||||||
|
TokenURI string `json:"token_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientCredentialsFile representation.
|
||||||
|
type ClientCredentialsFile struct {
|
||||||
|
Web *Config3LO `json:"web"`
|
||||||
|
Installed *Config3LO `json:"installed"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceAccountFile representation.
|
||||||
|
type ServiceAccountFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ProjectID string `json:"project_id"`
|
||||||
|
PrivateKeyID string `json:"private_key_id"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
ClientEmail string `json:"client_email"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
AuthURL string `json:"auth_uri"`
|
||||||
|
TokenURL string `json:"token_uri"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserCredentialsFile representation.
|
||||||
|
type UserCredentialsFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
QuotaProjectID string `json:"quota_project_id"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalAccountFile representation.
|
||||||
|
type ExternalAccountFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
Audience string `json:"audience"`
|
||||||
|
SubjectTokenType string `json:"subject_token_type"`
|
||||||
|
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
|
||||||
|
TokenURL string `json:"token_url"`
|
||||||
|
CredentialSource *CredentialSource `json:"credential_source,omitempty"`
|
||||||
|
TokenInfoURL string `json:"token_info_url"`
|
||||||
|
ServiceAccountImpersonation *ServiceAccountImpersonationInfo `json:"service_account_impersonation,omitempty"`
|
||||||
|
QuotaProjectID string `json:"quota_project_id"`
|
||||||
|
WorkforcePoolUserProject string `json:"workforce_pool_user_project"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalAccountAuthorizedUserFile representation.
|
||||||
|
type ExternalAccountAuthorizedUserFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Audience string `json:"audience"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
TokenURL string `json:"token_url"`
|
||||||
|
TokenInfoURL string `json:"token_info_url"`
|
||||||
|
RevokeURL string `json:"revoke_url"`
|
||||||
|
QuotaProjectID string `json:"quota_project_id"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialSource stores the information necessary to retrieve the credentials for the STS exchange.
|
||||||
|
//
|
||||||
|
// One field amongst File, URL, Certificate, and Executable 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"`
|
||||||
|
Executable *ExecutableConfig `json:"executable,omitempty"`
|
||||||
|
Certificate *CertificateConfig `json:"certificate"`
|
||||||
|
EnvironmentID string `json:"environment_id"` // TODO: Make type for this
|
||||||
|
RegionURL string `json:"region_url"`
|
||||||
|
RegionalCredVerificationURL string `json:"regional_cred_verification_url"`
|
||||||
|
CredVerificationURL string `json:"cred_verification_url"`
|
||||||
|
IMDSv2SessionTokenURL string `json:"imdsv2_session_token_url"`
|
||||||
|
Format *Format `json:"format,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format describes the format of a [CredentialSource].
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutableConfig represents the command to run for an executable
|
||||||
|
// [CredentialSource].
|
||||||
|
type ExecutableConfig struct {
|
||||||
|
Command string `json:"command"`
|
||||||
|
TimeoutMillis int `json:"timeout_millis"`
|
||||||
|
OutputFile string `json:"output_file"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateConfig represents the options used to set up X509 based workload
|
||||||
|
// [CredentialSource]
|
||||||
|
type CertificateConfig struct {
|
||||||
|
UseDefaultCertificateConfig bool `json:"use_default_certificate_config"`
|
||||||
|
CertificateConfigLocation string `json:"certificate_config_location"`
|
||||||
|
TrustChainPath string `json:"trust_chain_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceAccountImpersonationInfo has impersonation configuration.
|
||||||
|
type ServiceAccountImpersonationInfo struct {
|
||||||
|
TokenLifetimeSeconds int `json:"token_lifetime_seconds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonatedServiceAccountFile representation.
|
||||||
|
type ImpersonatedServiceAccountFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
|
||||||
|
Delegates []string `json:"delegates"`
|
||||||
|
Scopes []string `json:"scopes"`
|
||||||
|
CredSource json.RawMessage `json:"source_credentials"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GDCHServiceAccountFile represents the Google Distributed Cloud Hosted (GDCH) service identity file.
|
||||||
|
type GDCHServiceAccountFile struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
FormatVersion string `json:"format_version"`
|
||||||
|
Project string `json:"project"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
CertPath string `json:"ca_cert_path"`
|
||||||
|
PrivateKeyID string `json:"private_key_id"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
TokenURL string `json:"token_uri"`
|
||||||
|
UniverseDomain string `json:"universe_domain"`
|
||||||
|
}
|
||||||
99
vendor/cloud.google.com/go/auth/internal/credsfile/parse.go
generated
vendored
Normal file
99
vendor/cloud.google.com/go/auth/internal/credsfile/parse.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2023 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 credsfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseServiceAccount parses bytes into a [ServiceAccountFile].
|
||||||
|
func ParseServiceAccount(b []byte) (*ServiceAccountFile, error) {
|
||||||
|
var f *ServiceAccountFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseClientCredentials parses bytes into a
|
||||||
|
// [credsfile.ClientCredentialsFile].
|
||||||
|
func ParseClientCredentials(b []byte) (*ClientCredentialsFile, error) {
|
||||||
|
var f *ClientCredentialsFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseUserCredentials parses bytes into a [UserCredentialsFile].
|
||||||
|
func ParseUserCredentials(b []byte) (*UserCredentialsFile, error) {
|
||||||
|
var f *UserCredentialsFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseExternalAccount parses bytes into a [ExternalAccountFile].
|
||||||
|
func ParseExternalAccount(b []byte) (*ExternalAccountFile, error) {
|
||||||
|
var f *ExternalAccountFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseExternalAccountAuthorizedUser parses bytes into a
|
||||||
|
// [ExternalAccountAuthorizedUserFile].
|
||||||
|
func ParseExternalAccountAuthorizedUser(b []byte) (*ExternalAccountAuthorizedUserFile, error) {
|
||||||
|
var f *ExternalAccountAuthorizedUserFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseImpersonatedServiceAccount parses bytes into a
|
||||||
|
// [ImpersonatedServiceAccountFile].
|
||||||
|
func ParseImpersonatedServiceAccount(b []byte) (*ImpersonatedServiceAccountFile, error) {
|
||||||
|
var f *ImpersonatedServiceAccountFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGDCHServiceAccount parses bytes into a [GDCHServiceAccountFile].
|
||||||
|
func ParseGDCHServiceAccount(b []byte) (*GDCHServiceAccountFile, error) {
|
||||||
|
var f *GDCHServiceAccountFile
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileTypeChecker struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFileType determines the [CredentialType] based on bytes provided.
|
||||||
|
// Only returns error for json.Unmarshal.
|
||||||
|
func ParseFileType(b []byte) (string, error) {
|
||||||
|
var f fileTypeChecker
|
||||||
|
if err := json.Unmarshal(b, &f); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return f.Type, nil
|
||||||
|
}
|
||||||
285
vendor/cloud.google.com/go/auth/internal/internal.go
generated
vendored
Normal file
285
vendor/cloud.google.com/go/auth/internal/internal.go
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
// Copyright 2023 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 internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/compute/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TokenTypeBearer is the auth header prefix for bearer tokens.
|
||||||
|
TokenTypeBearer = "Bearer"
|
||||||
|
|
||||||
|
// QuotaProjectEnvVar is the environment variable for setting the quota
|
||||||
|
// project.
|
||||||
|
QuotaProjectEnvVar = "GOOGLE_CLOUD_QUOTA_PROJECT"
|
||||||
|
// UniverseDomainEnvVar is the environment variable for setting the default
|
||||||
|
// service domain for a given Cloud universe.
|
||||||
|
UniverseDomainEnvVar = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"
|
||||||
|
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
|
||||||
|
maxBodySize = 1 << 20
|
||||||
|
|
||||||
|
// DefaultUniverseDomain is the default value for universe domain.
|
||||||
|
// Universe domain is the default service domain for a given Cloud universe.
|
||||||
|
DefaultUniverseDomain = "googleapis.com"
|
||||||
|
|
||||||
|
// TrustBoundaryNoOp is a constant indicating no trust boundary is enforced.
|
||||||
|
TrustBoundaryNoOp = "0x0"
|
||||||
|
|
||||||
|
// TrustBoundaryDataKey is the key used to store trust boundary data in a token's metadata.
|
||||||
|
TrustBoundaryDataKey = "google.auth.trust_boundary_data"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clonableTransport interface {
|
||||||
|
Clone() *http.Transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultClient returns an [http.Client] with some defaults set. If
|
||||||
|
// the current [http.DefaultTransport] is a [clonableTransport], as
|
||||||
|
// is the case for an [*http.Transport], the clone will be used.
|
||||||
|
// Otherwise the [http.DefaultTransport] is used directly.
|
||||||
|
func DefaultClient() *http.Client {
|
||||||
|
if transport, ok := http.DefaultTransport.(clonableTransport); ok {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: transport.Clone(),
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &http.Client{
|
||||||
|
Transport: http.DefaultTransport,
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseKey converts the binary contents of a private key file
|
||||||
|
// to an crypto.Signer. It detects whether the private key is in a
|
||||||
|
// PEM container or not. If so, it extracts the the private key
|
||||||
|
// from PEM container before conversion. It only supports PEM
|
||||||
|
// containers with no passphrase.
|
||||||
|
func ParseKey(key []byte) (crypto.Signer, error) {
|
||||||
|
block, _ := pem.Decode(key)
|
||||||
|
if block != nil {
|
||||||
|
key = block.Bytes
|
||||||
|
}
|
||||||
|
var parsedKey crypto.PrivateKey
|
||||||
|
|
||||||
|
var errPKCS8, errPKCS1, errEC error
|
||||||
|
if parsedKey, errPKCS8 = x509.ParsePKCS8PrivateKey(key); errPKCS8 != nil {
|
||||||
|
if parsedKey, errPKCS1 = x509.ParsePKCS1PrivateKey(key); errPKCS1 != nil {
|
||||||
|
if parsedKey, errEC = x509.ParseECPrivateKey(key); errEC != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse private key. Tried PKCS8, PKCS1, and EC formats. Errors: [PKCS8: %v], [PKCS1: %v], [EC: %v]", errPKCS8, errPKCS1, errEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parsed, ok := parsedKey.(crypto.Signer)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("private key is not a signer")
|
||||||
|
}
|
||||||
|
return parsed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQuotaProject retrieves quota project with precedence being: override,
|
||||||
|
// environment variable, creds json file.
|
||||||
|
func GetQuotaProject(b []byte, override string) string {
|
||||||
|
if override != "" {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
if env := os.Getenv(QuotaProjectEnvVar); env != "" {
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
if b == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var v struct {
|
||||||
|
QuotaProject string `json:"quota_project_id"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return v.QuotaProject
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectID retrieves project with precedence being: override,
|
||||||
|
// environment variable, creds json file.
|
||||||
|
func GetProjectID(b []byte, override string) string {
|
||||||
|
if override != "" {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
if env := os.Getenv(projectEnvVar); env != "" {
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
if b == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var v struct {
|
||||||
|
ProjectID string `json:"project_id"` // standard service account key
|
||||||
|
Project string `json:"project"` // gdch key
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if v.ProjectID != "" {
|
||||||
|
return v.ProjectID
|
||||||
|
}
|
||||||
|
return v.Project
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRequest executes the provided req with the client. It reads the response
|
||||||
|
// body, closes it, and returns it.
|
||||||
|
func DoRequest(client *http.Client, req *http.Request) (*http.Response, []byte, error) {
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ReadAll(io.LimitReader(resp.Body, maxBodySize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return resp, body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAll consumes the whole reader and safely reads the content of its body
|
||||||
|
// with some overflow protection.
|
||||||
|
func ReadAll(r io.Reader) ([]byte, error) {
|
||||||
|
return io.ReadAll(io.LimitReader(r, maxBodySize))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticCredentialsProperty is a helper for creating static credentials
|
||||||
|
// properties.
|
||||||
|
func StaticCredentialsProperty(s string) StaticProperty {
|
||||||
|
return StaticProperty(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticProperty always returns that value of the underlying string.
|
||||||
|
type StaticProperty string
|
||||||
|
|
||||||
|
// GetProperty loads the properly value provided the given context.
|
||||||
|
func (p StaticProperty) GetProperty(context.Context) (string, error) {
|
||||||
|
return string(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeUniverseDomainProvider fetches the credentials universe domain from
|
||||||
|
// the google cloud metadata service.
|
||||||
|
type ComputeUniverseDomainProvider struct {
|
||||||
|
MetadataClient *metadata.Client
|
||||||
|
universeDomainOnce sync.Once
|
||||||
|
universeDomain string
|
||||||
|
universeDomainErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProperty fetches the credentials universe domain from the google cloud
|
||||||
|
// metadata service.
|
||||||
|
func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string, error) {
|
||||||
|
c.universeDomainOnce.Do(func() {
|
||||||
|
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx, c.MetadataClient)
|
||||||
|
})
|
||||||
|
if c.universeDomainErr != nil {
|
||||||
|
return "", c.universeDomainErr
|
||||||
|
}
|
||||||
|
return c.universeDomain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// httpGetMetadataUniverseDomain is a package var for unit test substitution.
|
||||||
|
var httpGetMetadataUniverseDomain = func(ctx context.Context, client *metadata.Client) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return client.GetWithContext(ctx, "universe/universe-domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMetadataUniverseDomain(ctx context.Context, client *metadata.Client) (string, error) {
|
||||||
|
universeDomain, err := httpGetMetadataUniverseDomain(ctx, client)
|
||||||
|
if err == nil {
|
||||||
|
return universeDomain, nil
|
||||||
|
}
|
||||||
|
if _, ok := err.(metadata.NotDefinedError); ok {
|
||||||
|
// http.StatusNotFound (404)
|
||||||
|
return DefaultUniverseDomain, nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatIAMServiceAccountResource sets a service account name in an IAM resource
|
||||||
|
// name.
|
||||||
|
func FormatIAMServiceAccountResource(name string) string {
|
||||||
|
return fmt.Sprintf("projects/-/serviceAccounts/%s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrustBoundaryData represents the trust boundary data associated with a token.
|
||||||
|
// It contains information about the regions or environments where the token is valid.
|
||||||
|
type TrustBoundaryData struct {
|
||||||
|
// Locations is the list of locations that the token is allowed to be used in.
|
||||||
|
Locations []string
|
||||||
|
// EncodedLocations represents the locations in an encoded format.
|
||||||
|
EncodedLocations string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTrustBoundaryData returns a new TrustBoundaryData with the specified locations and encoded locations.
|
||||||
|
func NewTrustBoundaryData(locations []string, encodedLocations string) *TrustBoundaryData {
|
||||||
|
// Ensure consistency by treating a nil slice as an empty slice.
|
||||||
|
if locations == nil {
|
||||||
|
locations = []string{}
|
||||||
|
}
|
||||||
|
locationsCopy := make([]string, len(locations))
|
||||||
|
copy(locationsCopy, locations)
|
||||||
|
return &TrustBoundaryData{
|
||||||
|
Locations: locationsCopy,
|
||||||
|
EncodedLocations: encodedLocations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNoOpTrustBoundaryData returns a new TrustBoundaryData with no restrictions.
|
||||||
|
func NewNoOpTrustBoundaryData() *TrustBoundaryData {
|
||||||
|
return &TrustBoundaryData{
|
||||||
|
Locations: []string{},
|
||||||
|
EncodedLocations: TrustBoundaryNoOp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrustBoundaryHeader returns the value for the x-allowed-locations header and a bool
|
||||||
|
// indicating if the header should be set. The return values are structured to
|
||||||
|
// handle three distinct states required by the backend:
|
||||||
|
// 1. Header not set: (value="", present=false) -> data is empty.
|
||||||
|
// 2. Header set to an empty string: (value="", present=true) -> data is a no-op.
|
||||||
|
// 3. Header set to a value: (value="...", present=true) -> data has locations.
|
||||||
|
func (t TrustBoundaryData) TrustBoundaryHeader() (value string, present bool) {
|
||||||
|
if t.EncodedLocations == "" {
|
||||||
|
// If the data is empty, the header should not be present.
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If data is not empty, the header should always be present.
|
||||||
|
present = true
|
||||||
|
value = ""
|
||||||
|
if t.EncodedLocations != TrustBoundaryNoOp {
|
||||||
|
value = t.EncodedLocations
|
||||||
|
}
|
||||||
|
// For a no-op, the backend requires an empty string.
|
||||||
|
return value, present
|
||||||
|
}
|
||||||
171
vendor/cloud.google.com/go/auth/internal/jwt/jwt.go
generated
vendored
Normal file
171
vendor/cloud.google.com/go/auth/internal/jwt/jwt.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
// Copyright 2023 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 jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HeaderAlgRSA256 is the RS256 [Header.Algorithm].
|
||||||
|
HeaderAlgRSA256 = "RS256"
|
||||||
|
// HeaderAlgES256 is the ES256 [Header.Algorithm].
|
||||||
|
HeaderAlgES256 = "ES256"
|
||||||
|
// HeaderType is the standard [Header.Type].
|
||||||
|
HeaderType = "JWT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Header represents a JWT header.
|
||||||
|
type Header struct {
|
||||||
|
Algorithm string `json:"alg"`
|
||||||
|
Type string `json:"typ"`
|
||||||
|
KeyID string `json:"kid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Header) encode() (string, error) {
|
||||||
|
b, err := json.Marshal(h)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claims represents the claims set of a JWT.
|
||||||
|
type Claims struct {
|
||||||
|
// Iss is the issuer JWT claim.
|
||||||
|
Iss string `json:"iss"`
|
||||||
|
// Scope is the scope JWT claim.
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
// Exp is the expiry JWT claim. If unset, default is in one hour from now.
|
||||||
|
Exp int64 `json:"exp"`
|
||||||
|
// Iat is the subject issued at claim. If unset, default is now.
|
||||||
|
Iat int64 `json:"iat"`
|
||||||
|
// Aud is the audience JWT claim. Optional.
|
||||||
|
Aud string `json:"aud"`
|
||||||
|
// Sub is the subject JWT claim. Optional.
|
||||||
|
Sub string `json:"sub,omitempty"`
|
||||||
|
// AdditionalClaims contains any additional non-standard JWT claims. Optional.
|
||||||
|
AdditionalClaims map[string]interface{} `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Claims) encode() (string, error) {
|
||||||
|
// Compensate for skew
|
||||||
|
now := time.Now().Add(-10 * time.Second)
|
||||||
|
if c.Iat == 0 {
|
||||||
|
c.Iat = now.Unix()
|
||||||
|
}
|
||||||
|
if c.Exp == 0 {
|
||||||
|
c.Exp = now.Add(time.Hour).Unix()
|
||||||
|
}
|
||||||
|
if c.Exp < c.Iat {
|
||||||
|
return "", fmt.Errorf("jwt: invalid Exp = %d; must be later than Iat = %d", c.Exp, c.Iat)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(c)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.AdditionalClaims) == 0 {
|
||||||
|
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal private claim set and then append it to b.
|
||||||
|
prv, err := json.Marshal(c.AdditionalClaims)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("invalid map of additional claims %v: %w", c.AdditionalClaims, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concatenate public and private claim JSON objects.
|
||||||
|
if !bytes.HasSuffix(b, []byte{'}'}) {
|
||||||
|
return "", fmt.Errorf("invalid JSON %s", b)
|
||||||
|
}
|
||||||
|
if !bytes.HasPrefix(prv, []byte{'{'}) {
|
||||||
|
return "", fmt.Errorf("invalid JSON %s", prv)
|
||||||
|
}
|
||||||
|
b[len(b)-1] = ',' // Replace closing curly brace with a comma.
|
||||||
|
b = append(b, prv[1:]...) // Append private claims.
|
||||||
|
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeJWS encodes the data using the provided key as a JSON web signature.
|
||||||
|
func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error) {
|
||||||
|
head, err := header.encode()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
claims, err := c.encode()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
ss := fmt.Sprintf("%s.%s", head, claims)
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(ss))
|
||||||
|
sig, err := signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA256)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeJWS decodes a claim set from a JWS payload.
|
||||||
|
func DecodeJWS(payload string) (*Claims, error) {
|
||||||
|
// decode returned id token to get expiry
|
||||||
|
s := strings.Split(payload, ".")
|
||||||
|
if len(s) < 2 {
|
||||||
|
return nil, errors.New("invalid token received")
|
||||||
|
}
|
||||||
|
decoded, err := base64.RawURLEncoding.DecodeString(s[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &Claims{}
|
||||||
|
if err := json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(bytes.NewBuffer(decoded)).Decode(&c.AdditionalClaims); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyJWS tests whether the provided JWT token's signature was produced by
|
||||||
|
// the private key associated with the provided public key.
|
||||||
|
func VerifyJWS(token string, key *rsa.PublicKey) error {
|
||||||
|
parts := strings.Split(token, ".")
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return errors.New("jwt: invalid token received, token must have 3 parts")
|
||||||
|
}
|
||||||
|
|
||||||
|
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), signatureString)
|
||||||
|
}
|
||||||
117
vendor/cloud.google.com/go/auth/internal/retry/retry.go
generated
vendored
Normal file
117
vendor/cloud.google.com/go/auth/internal/retry/retry.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2025 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 retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxRetryAttempts = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
syscallRetryable = func(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Retryer with the default backoff strategy.
|
||||||
|
func New() *Retryer {
|
||||||
|
return &Retryer{bo: &defaultBackoff{
|
||||||
|
cur: 100 * time.Millisecond,
|
||||||
|
max: 30 * time.Second,
|
||||||
|
mul: 2,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
type backoff interface {
|
||||||
|
Pause() time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retryer is a retryer for HTTP requests.
|
||||||
|
type Retryer struct {
|
||||||
|
bo backoff
|
||||||
|
attempts int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry determines if a request should be retried.
|
||||||
|
func (r *Retryer) 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
|
||||||
|
}
|
||||||
361
vendor/cloud.google.com/go/auth/internal/transport/cba.go
generated
vendored
Normal file
361
vendor/cloud.google.com/go/auth/internal/transport/cba.go
generated
vendored
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
// Copyright 2023 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 transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/cert"
|
||||||
|
"github.com/google/s2a-go"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
mTLSModeAlways = "always"
|
||||||
|
mTLSModeNever = "never"
|
||||||
|
mTLSModeAuto = "auto"
|
||||||
|
|
||||||
|
// Experimental: if true, the code will try MTLS with S2A as the default for transport security. Default value is false.
|
||||||
|
googleAPIUseS2AEnv = "EXPERIMENTAL_GOOGLE_API_USE_S2A"
|
||||||
|
googleAPIUseCertSource = "GOOGLE_API_USE_CLIENT_CERTIFICATE"
|
||||||
|
googleAPIUseMTLS = "GOOGLE_API_USE_MTLS_ENDPOINT"
|
||||||
|
googleAPIUseMTLSOld = "GOOGLE_API_USE_MTLS"
|
||||||
|
|
||||||
|
universeDomainPlaceholder = "UNIVERSE_DOMAIN"
|
||||||
|
|
||||||
|
mtlsMDSRoot = "/run/google-mds-mtls/root.crt"
|
||||||
|
mtlsMDSKey = "/run/google-mds-mtls/client.key"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type represents the type of transport used.
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TransportTypeUnknown represents an unknown transport type and is the default option.
|
||||||
|
TransportTypeUnknown Type = iota
|
||||||
|
// TransportTypeMTLSS2A represents the mTLS transport type using S2A.
|
||||||
|
TransportTypeMTLSS2A
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options is a struct that is duplicated information from the individual
|
||||||
|
// transport packages in order to avoid cyclic deps. It correlates 1:1 with
|
||||||
|
// fields on httptransport.Options and grpctransport.Options.
|
||||||
|
type Options struct {
|
||||||
|
Endpoint string
|
||||||
|
DefaultEndpointTemplate string
|
||||||
|
DefaultMTLSEndpoint string
|
||||||
|
ClientCertProvider cert.Provider
|
||||||
|
Client *http.Client
|
||||||
|
UniverseDomain string
|
||||||
|
EnableDirectPath bool
|
||||||
|
EnableDirectPathXds bool
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUniverseDomain returns the default service domain for a given Cloud
|
||||||
|
// universe.
|
||||||
|
func (o *Options) getUniverseDomain() string {
|
||||||
|
if o.UniverseDomain == "" {
|
||||||
|
return internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
return o.UniverseDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
// isUniverseDomainGDU returns true if the universe domain is the default Google
|
||||||
|
// universe.
|
||||||
|
func (o *Options) isUniverseDomainGDU() bool {
|
||||||
|
return o.getUniverseDomain() == internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultEndpoint returns the DefaultEndpointTemplate merged with the
|
||||||
|
// universe domain if the DefaultEndpointTemplate is set, otherwise returns an
|
||||||
|
// empty string.
|
||||||
|
func (o *Options) defaultEndpoint() string {
|
||||||
|
if o.DefaultEndpointTemplate == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Replace(o.DefaultEndpointTemplate, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultMTLSEndpoint returns the DefaultMTLSEndpointTemplate merged with the
|
||||||
|
// universe domain if the DefaultMTLSEndpointTemplate is set, otherwise returns an
|
||||||
|
// empty string.
|
||||||
|
func (o *Options) defaultMTLSEndpoint() string {
|
||||||
|
if o.DefaultMTLSEndpoint == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Replace(o.DefaultMTLSEndpoint, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergedEndpoint merges a user-provided Endpoint of format host[:port] with the
|
||||||
|
// default endpoint.
|
||||||
|
func (o *Options) mergedEndpoint() (string, error) {
|
||||||
|
defaultEndpoint := o.defaultEndpoint()
|
||||||
|
u, err := url.Parse(fixScheme(defaultEndpoint))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.Replace(defaultEndpoint, u.Host, o.Endpoint, 1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixScheme(baseURL string) string {
|
||||||
|
if !strings.Contains(baseURL, "://") {
|
||||||
|
baseURL = "https://" + baseURL
|
||||||
|
}
|
||||||
|
return baseURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// GRPCTransportCredentials embeds interface TransportCredentials with additional data.
|
||||||
|
type GRPCTransportCredentials struct {
|
||||||
|
credentials.TransportCredentials
|
||||||
|
Endpoint string
|
||||||
|
TransportType Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGRPCTransportCredsAndEndpoint returns an instance of
|
||||||
|
// [google.golang.org/grpc/credentials.TransportCredentials], and the
|
||||||
|
// corresponding endpoint and transport type to use for GRPC client.
|
||||||
|
func GetGRPCTransportCredsAndEndpoint(opts *Options) (*GRPCTransportCredentials, error) {
|
||||||
|
config, err := getTransportConfig(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTransportCreds := credentials.NewTLS(&tls.Config{
|
||||||
|
GetClientCertificate: config.clientCertSource,
|
||||||
|
})
|
||||||
|
|
||||||
|
var s2aAddr string
|
||||||
|
var transportCredsForS2A credentials.TransportCredentials
|
||||||
|
|
||||||
|
if config.mtlsS2AAddress != "" {
|
||||||
|
s2aAddr = config.mtlsS2AAddress
|
||||||
|
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
||||||
|
if config.s2aAddress != "" {
|
||||||
|
s2aAddr = config.s2aAddress
|
||||||
|
} else {
|
||||||
|
return &GRPCTransportCredentials{defaultTransportCreds, config.endpoint, TransportTypeUnknown}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if config.s2aAddress != "" {
|
||||||
|
s2aAddr = config.s2aAddress
|
||||||
|
} else {
|
||||||
|
return &GRPCTransportCredentials{defaultTransportCreds, config.endpoint, TransportTypeUnknown}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s2aTransportCreds, err := s2a.NewClientCreds(&s2a.ClientOptions{
|
||||||
|
S2AAddress: s2aAddr,
|
||||||
|
TransportCreds: transportCredsForS2A,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// Use default if we cannot initialize S2A client transport credentials.
|
||||||
|
return &GRPCTransportCredentials{defaultTransportCreds, config.endpoint, TransportTypeUnknown}, nil
|
||||||
|
}
|
||||||
|
return &GRPCTransportCredentials{s2aTransportCreds, config.s2aMTLSEndpoint, TransportTypeMTLSS2A}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTTPTransportConfig returns a client certificate source and a function for
|
||||||
|
// dialing MTLS with S2A.
|
||||||
|
func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context, string, string) (net.Conn, error), error) {
|
||||||
|
config, err := getTransportConfig(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var s2aAddr string
|
||||||
|
var transportCredsForS2A credentials.TransportCredentials
|
||||||
|
|
||||||
|
if config.mtlsS2AAddress != "" {
|
||||||
|
s2aAddr = config.mtlsS2AAddress
|
||||||
|
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
||||||
|
if config.s2aAddress != "" {
|
||||||
|
s2aAddr = config.s2aAddress
|
||||||
|
} else {
|
||||||
|
return config.clientCertSource, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if config.s2aAddress != "" {
|
||||||
|
s2aAddr = config.s2aAddress
|
||||||
|
} else {
|
||||||
|
return config.clientCertSource, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dialTLSContextFunc := s2a.NewS2ADialTLSContextFunc(&s2a.ClientOptions{
|
||||||
|
S2AAddress: s2aAddr,
|
||||||
|
TransportCreds: transportCredsForS2A,
|
||||||
|
})
|
||||||
|
return nil, dialTLSContextFunc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadMTLSMDSTransportCreds(mtlsMDSRootFile, mtlsMDSKeyFile string) (credentials.TransportCredentials, error) {
|
||||||
|
rootPEM, err := os.ReadFile(mtlsMDSRootFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
ok := caCertPool.AppendCertsFromPEM(rootPEM)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("failed to load MTLS MDS root certificate")
|
||||||
|
}
|
||||||
|
// The mTLS MDS credentials are formatted as the concatenation of a PEM-encoded certificate chain
|
||||||
|
// followed by a PEM-encoded private key. For this reason, the concatenation is passed in to the
|
||||||
|
// tls.X509KeyPair function as both the certificate chain and private key arguments.
|
||||||
|
cert, err := tls.LoadX509KeyPair(mtlsMDSKeyFile, mtlsMDSKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsConfig := tls.Config{
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
MinVersion: tls.VersionTLS13,
|
||||||
|
}
|
||||||
|
return credentials.NewTLS(&tlsConfig), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransportConfig(opts *Options) (*transportConfig, error) {
|
||||||
|
clientCertSource, err := GetClientCertificateProvider(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
endpoint, err := getEndpoint(opts, clientCertSource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultTransportConfig := transportConfig{
|
||||||
|
clientCertSource: clientCertSource,
|
||||||
|
endpoint: endpoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !shouldUseS2A(clientCertSource, opts) {
|
||||||
|
return &defaultTransportConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s2aAddress := GetS2AAddress(opts.Logger)
|
||||||
|
mtlsS2AAddress := GetMTLSS2AAddress(opts.Logger)
|
||||||
|
if s2aAddress == "" && mtlsS2AAddress == "" {
|
||||||
|
return &defaultTransportConfig, nil
|
||||||
|
}
|
||||||
|
return &transportConfig{
|
||||||
|
clientCertSource: clientCertSource,
|
||||||
|
endpoint: endpoint,
|
||||||
|
s2aAddress: s2aAddress,
|
||||||
|
mtlsS2AAddress: mtlsS2AAddress,
|
||||||
|
s2aMTLSEndpoint: opts.defaultMTLSEndpoint(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientCertificateProvider returns a default client certificate source, if
|
||||||
|
// not provided by the user.
|
||||||
|
//
|
||||||
|
// A nil default source can be returned if the source does not exist. Any exceptions
|
||||||
|
// encountered while initializing the default source will be reported as client
|
||||||
|
// error (ex. corrupt metadata file).
|
||||||
|
func GetClientCertificateProvider(opts *Options) (cert.Provider, error) {
|
||||||
|
if !isClientCertificateEnabled(opts) {
|
||||||
|
return nil, nil
|
||||||
|
} else if opts.ClientCertProvider != nil {
|
||||||
|
return opts.ClientCertProvider, nil
|
||||||
|
}
|
||||||
|
return cert.DefaultProvider()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// isClientCertificateEnabled returns true by default for all GDU universe domain, unless explicitly overridden by env var
|
||||||
|
func isClientCertificateEnabled(opts *Options) bool {
|
||||||
|
if value, ok := os.LookupEnv(googleAPIUseCertSource); ok {
|
||||||
|
// error as false is OK
|
||||||
|
b, _ := strconv.ParseBool(value)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return opts.isUniverseDomainGDU()
|
||||||
|
}
|
||||||
|
|
||||||
|
type transportConfig struct {
|
||||||
|
// The client certificate source.
|
||||||
|
clientCertSource cert.Provider
|
||||||
|
// The corresponding endpoint to use based on client certificate source.
|
||||||
|
endpoint string
|
||||||
|
// The plaintext S2A address if it can be used, otherwise an empty string.
|
||||||
|
s2aAddress string
|
||||||
|
// The MTLS S2A address if it can be used, otherwise an empty string.
|
||||||
|
mtlsS2AAddress string
|
||||||
|
// The MTLS endpoint to use with S2A.
|
||||||
|
s2aMTLSEndpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEndpoint returns the endpoint for the service, taking into account the
|
||||||
|
// user-provided endpoint override "settings.Endpoint".
|
||||||
|
//
|
||||||
|
// If no endpoint override is specified, we will either return the default
|
||||||
|
// endpoint or the default mTLS endpoint if a client certificate is available.
|
||||||
|
//
|
||||||
|
// You can override the default endpoint choice (mTLS vs. regular) by setting
|
||||||
|
// the GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
|
||||||
|
//
|
||||||
|
// If the endpoint override is an address (host:port) rather than full base
|
||||||
|
// URL (ex. https://...), then the user-provided address will be merged into
|
||||||
|
// the default endpoint. For example, WithEndpoint("myhost:8000") and
|
||||||
|
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return
|
||||||
|
// "https://myhost:8080/bar/baz". Note that this does not apply to the mTLS
|
||||||
|
// endpoint.
|
||||||
|
func getEndpoint(opts *Options, clientCertSource cert.Provider) (string, error) {
|
||||||
|
if opts.Endpoint == "" {
|
||||||
|
mtlsMode := getMTLSMode()
|
||||||
|
if mtlsMode == mTLSModeAlways || (clientCertSource != nil && mtlsMode == mTLSModeAuto) {
|
||||||
|
return opts.defaultMTLSEndpoint(), nil
|
||||||
|
}
|
||||||
|
return opts.defaultEndpoint(), nil
|
||||||
|
}
|
||||||
|
if strings.Contains(opts.Endpoint, "://") {
|
||||||
|
// User passed in a full URL path, use it verbatim.
|
||||||
|
return opts.Endpoint, nil
|
||||||
|
}
|
||||||
|
if opts.defaultEndpoint() == "" {
|
||||||
|
// If DefaultEndpointTemplate is not configured,
|
||||||
|
// use the user provided endpoint verbatim. This allows a naked
|
||||||
|
// "host[:port]" URL to be used with GRPC Direct Path.
|
||||||
|
return opts.Endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume user-provided endpoint is host[:port], merge it with the default endpoint.
|
||||||
|
return opts.mergedEndpoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMTLSMode() string {
|
||||||
|
mode := os.Getenv(googleAPIUseMTLS)
|
||||||
|
if mode == "" {
|
||||||
|
mode = os.Getenv(googleAPIUseMTLSOld) // Deprecated.
|
||||||
|
}
|
||||||
|
if mode == "" {
|
||||||
|
return mTLSModeAuto
|
||||||
|
}
|
||||||
|
return strings.ToLower(mode)
|
||||||
|
}
|
||||||
65
vendor/cloud.google.com/go/auth/internal/transport/cert/default_cert.go
generated
vendored
Normal file
65
vendor/cloud.google.com/go/auth/internal/transport/cert/default_cert.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2023 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 cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// defaultCertData holds all the variables pertaining to
|
||||||
|
// the default certificate provider created by [DefaultProvider].
|
||||||
|
//
|
||||||
|
// A singleton model is used to allow the provider to be reused
|
||||||
|
// by the transport layer. As mentioned in [DefaultProvider] (provider nil, nil)
|
||||||
|
// may be returned to indicate a default provider could not be found, which
|
||||||
|
// will skip extra tls config in the transport layer .
|
||||||
|
type defaultCertData struct {
|
||||||
|
once sync.Once
|
||||||
|
provider Provider
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultCert defaultCertData
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider is a function that can be passed into crypto/tls.Config.GetClientCertificate.
|
||||||
|
type Provider func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
|
||||||
|
|
||||||
|
// errSourceUnavailable is a sentinel error to indicate certificate source is unavailable.
|
||||||
|
var errSourceUnavailable = errors.New("certificate source is unavailable")
|
||||||
|
|
||||||
|
// DefaultProvider returns a certificate source using the preferred EnterpriseCertificateProxySource.
|
||||||
|
// If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource.
|
||||||
|
//
|
||||||
|
// If neither source is available (due to missing configurations), a nil Source and a nil Error are
|
||||||
|
// returned to indicate that a default certificate source is unavailable.
|
||||||
|
func DefaultProvider() (Provider, error) {
|
||||||
|
defaultCert.once.Do(func() {
|
||||||
|
defaultCert.provider, defaultCert.err = NewWorkloadX509CertProvider("")
|
||||||
|
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
||||||
|
defaultCert.provider, defaultCert.err = NewEnterpriseCertificateProxyProvider("")
|
||||||
|
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
||||||
|
defaultCert.provider, defaultCert.err = NewSecureConnectProvider("")
|
||||||
|
if errors.Is(defaultCert.err, errSourceUnavailable) {
|
||||||
|
defaultCert.provider, defaultCert.err = nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return defaultCert.provider, defaultCert.err
|
||||||
|
}
|
||||||
54
vendor/cloud.google.com/go/auth/internal/transport/cert/enterprise_cert.go
generated
vendored
Normal file
54
vendor/cloud.google.com/go/auth/internal/transport/cert/enterprise_cert.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2023 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 cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"github.com/googleapis/enterprise-certificate-proxy/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ecpSource struct {
|
||||||
|
key *client.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnterpriseCertificateProxyProvider creates a certificate source
|
||||||
|
// using the Enterprise Certificate Proxy client, which delegates
|
||||||
|
// certifcate related operations to an OS-specific "signer binary"
|
||||||
|
// that communicates with the native keystore (ex. keychain on MacOS).
|
||||||
|
//
|
||||||
|
// The configFilePath points to a config file containing relevant parameters
|
||||||
|
// such as the certificate issuer and the location of the signer binary.
|
||||||
|
// If configFilePath is empty, the client will attempt to load the config from
|
||||||
|
// a well-known gcloud location.
|
||||||
|
func NewEnterpriseCertificateProxyProvider(configFilePath string) (Provider, error) {
|
||||||
|
key, err := client.Cred(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
// TODO(codyoss): once this is fixed upstream can handle this error a
|
||||||
|
// little better here. But be safe for now and assume unavailable.
|
||||||
|
return nil, errSourceUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
return (&ecpSource{
|
||||||
|
key: key,
|
||||||
|
}).getClientCertificate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ecpSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||||
|
var cert tls.Certificate
|
||||||
|
cert.PrivateKey = s.key
|
||||||
|
cert.Certificate = s.key.CertificateChain()
|
||||||
|
return &cert, nil
|
||||||
|
}
|
||||||
124
vendor/cloud.google.com/go/auth/internal/transport/cert/secureconnect_cert.go
generated
vendored
Normal file
124
vendor/cloud.google.com/go/auth/internal/transport/cert/secureconnect_cert.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2023 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 cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
metadataPath = ".secureConnect"
|
||||||
|
metadataFile = "context_aware_metadata.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type secureConnectSource struct {
|
||||||
|
metadata secureConnectMetadata
|
||||||
|
|
||||||
|
// Cache the cert to avoid executing helper command repeatedly.
|
||||||
|
cachedCertMutex sync.Mutex
|
||||||
|
cachedCert *tls.Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
type secureConnectMetadata struct {
|
||||||
|
Cmd []string `json:"cert_provider_command"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecureConnectProvider creates a certificate source using
|
||||||
|
// the Secure Connect Helper and its associated metadata file.
|
||||||
|
//
|
||||||
|
// The configFilePath points to the location of the context aware metadata file.
|
||||||
|
// If configFilePath is empty, use the default context aware metadata location.
|
||||||
|
func NewSecureConnectProvider(configFilePath string) (Provider, error) {
|
||||||
|
if configFilePath == "" {
|
||||||
|
user, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
// Error locating the default config means Secure Connect is not supported.
|
||||||
|
return nil, errSourceUnavailable
|
||||||
|
}
|
||||||
|
configFilePath = filepath.Join(user.HomeDir, metadataPath, metadataFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.ReadFile(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
// Config file missing means Secure Connect is not supported.
|
||||||
|
// There are non-os.ErrNotExist errors that may be returned.
|
||||||
|
// (e.g. if the home directory is /dev/null, *nix systems will
|
||||||
|
// return ENOTDIR instead of ENOENT)
|
||||||
|
return nil, errSourceUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata secureConnectMetadata
|
||||||
|
if err := json.Unmarshal(file, &metadata); err != nil {
|
||||||
|
return nil, fmt.Errorf("cert: could not parse JSON in %q: %w", configFilePath, err)
|
||||||
|
}
|
||||||
|
if err := validateMetadata(metadata); err != nil {
|
||||||
|
return nil, fmt.Errorf("cert: invalid config in %q: %w", configFilePath, err)
|
||||||
|
}
|
||||||
|
return (&secureConnectSource{
|
||||||
|
metadata: metadata,
|
||||||
|
}).getClientCertificate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateMetadata(metadata secureConnectMetadata) error {
|
||||||
|
if len(metadata.Cmd) == 0 {
|
||||||
|
return errors.New("empty cert_provider_command")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *secureConnectSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||||
|
s.cachedCertMutex.Lock()
|
||||||
|
defer s.cachedCertMutex.Unlock()
|
||||||
|
if s.cachedCert != nil && !isCertificateExpired(s.cachedCert) {
|
||||||
|
return s.cachedCert, nil
|
||||||
|
}
|
||||||
|
// Expand OS environment variables in the cert provider command such as "$HOME".
|
||||||
|
for i := 0; i < len(s.metadata.Cmd); i++ {
|
||||||
|
s.metadata.Cmd[i] = os.ExpandEnv(s.metadata.Cmd[i])
|
||||||
|
}
|
||||||
|
command := s.metadata.Cmd
|
||||||
|
data, err := exec.Command(command[0], command[1:]...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cert, err := tls.X509KeyPair(data, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.cachedCert = &cert
|
||||||
|
return &cert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isCertificateExpired returns true if the given cert is expired or invalid.
|
||||||
|
func isCertificateExpired(cert *tls.Certificate) bool {
|
||||||
|
if len(cert.Certificate) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
parsed, err := x509.ParseCertificate(cert.Certificate[0])
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return time.Now().After(parsed.NotAfter)
|
||||||
|
}
|
||||||
138
vendor/cloud.google.com/go/auth/internal/transport/cert/workload_cert.go
generated
vendored
Normal file
138
vendor/cloud.google.com/go/auth/internal/transport/cert/workload_cert.go
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2024 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 cert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/googleapis/enterprise-certificate-proxy/client/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type certConfigs struct {
|
||||||
|
Workload *workloadSource `json:"workload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type workloadSource struct {
|
||||||
|
CertPath string `json:"cert_path"`
|
||||||
|
KeyPath string `json:"key_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type certificateConfig struct {
|
||||||
|
CertConfigs certConfigs `json:"cert_configs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getconfigFilePath determines the path to the certificate configuration file.
|
||||||
|
// It first checks for the presence of an environment variable that specifies
|
||||||
|
// the file path. If the environment variable is not set, it falls back to
|
||||||
|
// a default configuration file path.
|
||||||
|
func getconfigFilePath() string {
|
||||||
|
envFilePath := util.GetConfigFilePathFromEnv()
|
||||||
|
if envFilePath != "" {
|
||||||
|
return envFilePath
|
||||||
|
}
|
||||||
|
return util.GetDefaultConfigFilePath()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCertificatePath retrieves the certificate file path from the provided
|
||||||
|
// configuration file. If the configFilePath is empty, it attempts to load
|
||||||
|
// the configuration from a well-known gcloud location.
|
||||||
|
// This function is exposed to allow other packages, such as the
|
||||||
|
// externalaccount package, to retrieve the certificate path without needing
|
||||||
|
// to load the entire certificate configuration.
|
||||||
|
func GetCertificatePath(configFilePath string) (string, error) {
|
||||||
|
if configFilePath == "" {
|
||||||
|
configFilePath = getconfigFilePath()
|
||||||
|
}
|
||||||
|
certFile, _, err := getCertAndKeyFiles(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return certFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWorkloadX509CertProvider creates a certificate source
|
||||||
|
// that reads a certificate and private key file from the local file system.
|
||||||
|
// This is intended to be used for workload identity federation.
|
||||||
|
//
|
||||||
|
// The configFilePath points to a config file containing relevant parameters
|
||||||
|
// such as the certificate and key file paths.
|
||||||
|
// If configFilePath is empty, the client will attempt to load the config from
|
||||||
|
// a well-known gcloud location.
|
||||||
|
func NewWorkloadX509CertProvider(configFilePath string) (Provider, error) {
|
||||||
|
if configFilePath == "" {
|
||||||
|
configFilePath = getconfigFilePath()
|
||||||
|
}
|
||||||
|
certFile, keyFile, err := getCertAndKeyFiles(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
source := &workloadSource{
|
||||||
|
CertPath: certFile,
|
||||||
|
KeyPath: keyFile,
|
||||||
|
}
|
||||||
|
return source.getClientCertificate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClientCertificate attempts to load the certificate and key from the files specified in the
|
||||||
|
// certificate config.
|
||||||
|
func (s *workloadSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||||
|
cert, err := tls.LoadX509KeyPair(s.CertPath, s.KeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &cert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCertAndKeyFiles attempts to read the provided config file and return the certificate and private
|
||||||
|
// key file paths.
|
||||||
|
func getCertAndKeyFiles(configFilePath string) (string, string, error) {
|
||||||
|
jsonFile, err := os.Open(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", errSourceUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
byteValue, err := io.ReadAll(jsonFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var config certificateConfig
|
||||||
|
if err := json.Unmarshal(byteValue, &config); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.CertConfigs.Workload == nil {
|
||||||
|
return "", "", errSourceUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
certFile := config.CertConfigs.Workload.CertPath
|
||||||
|
keyFile := config.CertConfigs.Workload.KeyPath
|
||||||
|
|
||||||
|
if certFile == "" {
|
||||||
|
return "", "", errors.New("certificate configuration is missing the certificate file location")
|
||||||
|
}
|
||||||
|
|
||||||
|
if keyFile == "" {
|
||||||
|
return "", "", errors.New("certificate configuration is missing the key file location")
|
||||||
|
}
|
||||||
|
|
||||||
|
return certFile, keyFile, nil
|
||||||
|
}
|
||||||
61
vendor/cloud.google.com/go/auth/internal/transport/headers/headers.go
generated
vendored
Normal file
61
vendor/cloud.google.com/go/auth/internal/transport/headers/headers.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2025 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 headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetAuthHeader uses the provided token to set the Authorization and trust
|
||||||
|
// boundary headers on a request. If the token.Type is empty, the type is
|
||||||
|
// assumed to be Bearer.
|
||||||
|
func SetAuthHeader(token *auth.Token, req *http.Request) {
|
||||||
|
typ := token.Type
|
||||||
|
if typ == "" {
|
||||||
|
typ = internal.TokenTypeBearer
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", typ+" "+token.Value)
|
||||||
|
|
||||||
|
if headerVal, setHeader := getTrustBoundaryHeader(token); setHeader {
|
||||||
|
req.Header.Set("x-allowed-locations", headerVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthMetadata uses the provided token to set the Authorization and trust
|
||||||
|
// boundary metadata. If the token.Type is empty, the type is assumed to be
|
||||||
|
// Bearer.
|
||||||
|
func SetAuthMetadata(token *auth.Token, m map[string]string) {
|
||||||
|
typ := token.Type
|
||||||
|
if typ == "" {
|
||||||
|
typ = internal.TokenTypeBearer
|
||||||
|
}
|
||||||
|
m["authorization"] = typ + " " + token.Value
|
||||||
|
|
||||||
|
if headerVal, setHeader := getTrustBoundaryHeader(token); setHeader {
|
||||||
|
m["x-allowed-locations"] = headerVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTrustBoundaryHeader(token *auth.Token) (val string, present bool) {
|
||||||
|
if data, ok := token.Metadata[internal.TrustBoundaryDataKey]; ok {
|
||||||
|
if tbd, ok := data.(internal.TrustBoundaryData); ok {
|
||||||
|
return tbd.TrustBoundaryHeader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
138
vendor/cloud.google.com/go/auth/internal/transport/s2a.go
generated
vendored
Normal file
138
vendor/cloud.google.com/go/auth/internal/transport/s2a.go
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2023 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 transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal/transport/cert"
|
||||||
|
"cloud.google.com/go/compute/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
configEndpointSuffix = "instance/platform-security/auto-mtls-configuration"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mtlsConfiguration *mtlsConfig
|
||||||
|
|
||||||
|
mtlsOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetS2AAddress returns the S2A address to be reached via plaintext connection.
|
||||||
|
// Returns empty string if not set or invalid.
|
||||||
|
func GetS2AAddress(logger *slog.Logger) string {
|
||||||
|
getMetadataMTLSAutoConfig(logger)
|
||||||
|
if !mtlsConfiguration.valid() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return mtlsConfiguration.S2A.PlaintextAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMTLSS2AAddress returns the S2A address to be reached via MTLS connection.
|
||||||
|
// Returns empty string if not set or invalid.
|
||||||
|
func GetMTLSS2AAddress(logger *slog.Logger) string {
|
||||||
|
getMetadataMTLSAutoConfig(logger)
|
||||||
|
if !mtlsConfiguration.valid() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return mtlsConfiguration.S2A.MTLSAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// mtlsConfig contains the configuration for establishing MTLS connections with Google APIs.
|
||||||
|
type mtlsConfig struct {
|
||||||
|
S2A *s2aAddresses `json:"s2a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mtlsConfig) valid() bool {
|
||||||
|
return c != nil && c.S2A != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// s2aAddresses contains the plaintext and/or MTLS S2A addresses.
|
||||||
|
type s2aAddresses struct {
|
||||||
|
// PlaintextAddress is the plaintext address to reach S2A
|
||||||
|
PlaintextAddress string `json:"plaintext_address"`
|
||||||
|
// MTLSAddress is the MTLS address to reach S2A
|
||||||
|
MTLSAddress string `json:"mtls_address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMetadataMTLSAutoConfig(logger *slog.Logger) {
|
||||||
|
var err error
|
||||||
|
mtlsOnce.Do(func() {
|
||||||
|
mtlsConfiguration, err = queryConfig(logger)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Getting MTLS config failed: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpGetMetadataMTLSConfig = func(logger *slog.Logger) (string, error) {
|
||||||
|
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
||||||
|
Logger: logger,
|
||||||
|
})
|
||||||
|
return metadataClient.GetWithContext(context.Background(), configEndpointSuffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryConfig(logger *slog.Logger) (*mtlsConfig, error) {
|
||||||
|
resp, err := httpGetMetadataMTLSConfig(logger)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("querying MTLS config from MDS endpoint failed: %w", err)
|
||||||
|
}
|
||||||
|
var config mtlsConfig
|
||||||
|
err = json.Unmarshal([]byte(resp), &config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshalling MTLS config from MDS endpoint failed: %w", err)
|
||||||
|
}
|
||||||
|
if config.S2A == nil {
|
||||||
|
return nil, fmt.Errorf("returned MTLS config from MDS endpoint is invalid: %v", config)
|
||||||
|
}
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldUseS2A(clientCertSource cert.Provider, opts *Options) bool {
|
||||||
|
// If client cert is found, use that over S2A.
|
||||||
|
if clientCertSource != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// If EXPERIMENTAL_GOOGLE_API_USE_S2A is not set to true, skip S2A.
|
||||||
|
if !isGoogleS2AEnabled() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// If DefaultMTLSEndpoint is not set or has endpoint override, skip S2A.
|
||||||
|
if opts.DefaultMTLSEndpoint == "" || opts.Endpoint != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// If custom HTTP client is provided, skip S2A.
|
||||||
|
if opts.Client != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// If directPath is enabled, skip S2A.
|
||||||
|
return !opts.EnableDirectPath && !opts.EnableDirectPathXds
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGoogleS2AEnabled() bool {
|
||||||
|
b, err := strconv.ParseBool(os.Getenv(googleAPIUseS2AEnv))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
107
vendor/cloud.google.com/go/auth/internal/transport/transport.go
generated
vendored
Normal file
107
vendor/cloud.google.com/go/auth/internal/transport/transport.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2023 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 transport provided internal helpers for the two transport packages
|
||||||
|
// (grpctransport and httptransport).
|
||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CloneDetectOptions clones a user set detect option into some new memory that
|
||||||
|
// we can internally manipulate before sending onto the detect package.
|
||||||
|
func CloneDetectOptions(oldDo *credentials.DetectOptions) *credentials.DetectOptions {
|
||||||
|
if oldDo == nil {
|
||||||
|
// it is valid for users not to set this, but we will need to to default
|
||||||
|
// some options for them in this case so return some initialized memory
|
||||||
|
// to work with.
|
||||||
|
return &credentials.DetectOptions{}
|
||||||
|
}
|
||||||
|
newDo := &credentials.DetectOptions{
|
||||||
|
// Simple types
|
||||||
|
TokenBindingType: oldDo.TokenBindingType,
|
||||||
|
Audience: oldDo.Audience,
|
||||||
|
Subject: oldDo.Subject,
|
||||||
|
EarlyTokenRefresh: oldDo.EarlyTokenRefresh,
|
||||||
|
TokenURL: oldDo.TokenURL,
|
||||||
|
STSAudience: oldDo.STSAudience,
|
||||||
|
CredentialsFile: oldDo.CredentialsFile,
|
||||||
|
UseSelfSignedJWT: oldDo.UseSelfSignedJWT,
|
||||||
|
UniverseDomain: oldDo.UniverseDomain,
|
||||||
|
|
||||||
|
// These fields are pointer types that we just want to use exactly as
|
||||||
|
// the user set, copy the ref
|
||||||
|
Client: oldDo.Client,
|
||||||
|
Logger: oldDo.Logger,
|
||||||
|
AuthHandlerOptions: oldDo.AuthHandlerOptions,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smartly size this memory and copy below.
|
||||||
|
if len(oldDo.CredentialsJSON) > 0 {
|
||||||
|
newDo.CredentialsJSON = make([]byte, len(oldDo.CredentialsJSON))
|
||||||
|
copy(newDo.CredentialsJSON, oldDo.CredentialsJSON)
|
||||||
|
}
|
||||||
|
if len(oldDo.Scopes) > 0 {
|
||||||
|
newDo.Scopes = make([]string, len(oldDo.Scopes))
|
||||||
|
copy(newDo.Scopes, oldDo.Scopes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUniverseDomain verifies that the universe domain configured for the
|
||||||
|
// client matches the universe domain configured for the credentials.
|
||||||
|
func ValidateUniverseDomain(clientUniverseDomain, credentialsUniverseDomain string) error {
|
||||||
|
if clientUniverseDomain != credentialsUniverseDomain {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"the configured universe domain (%q) does not match the universe "+
|
||||||
|
"domain found in the credentials (%q). If you haven't configured "+
|
||||||
|
"the universe domain explicitly, \"googleapis.com\" is the default",
|
||||||
|
clientUniverseDomain,
|
||||||
|
credentialsUniverseDomain)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultHTTPClientWithTLS constructs an HTTPClient using the provided tlsConfig, to support mTLS.
|
||||||
|
func DefaultHTTPClientWithTLS(tlsConfig *tls.Config) *http.Client {
|
||||||
|
trans := BaseTransport()
|
||||||
|
trans.TLSClientConfig = tlsConfig
|
||||||
|
return &http.Client{Transport: trans}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseTransport returns a default [http.Transport] which can be used if
|
||||||
|
// [http.DefaultTransport] has been overwritten.
|
||||||
|
func BaseTransport() *http.Transport {
|
||||||
|
return &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialContext: (&net.Dialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
DualStack: true,
|
||||||
|
}).DialContext,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
MaxIdleConnsPerHost: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
100
vendor/cloud.google.com/go/auth/internal/trustboundary/external_accounts_config_providers.go
generated
vendored
Normal file
100
vendor/cloud.google.com/go/auth/internal/trustboundary/external_accounts_config_providers.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2025 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 trustboundary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
workloadAllowedLocationsEndpoint = "https://iamcredentials.%s/v1/projects/%s/locations/global/workloadIdentityPools/%s/allowedLocations"
|
||||||
|
workforceAllowedLocationsEndpoint = "https://iamcredentials.%s/v1/locations/global/workforcePools/%s/allowedLocations"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
workforceAudiencePattern = regexp.MustCompile(`//iam\.([^/]+)/locations/global/workforcePools/([^/]+)`)
|
||||||
|
workloadAudiencePattern = regexp.MustCompile(`//iam\.([^/]+)/projects/([^/]+)/locations/global/workloadIdentityPools/([^/]+)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewExternalAccountConfigProvider creates a new ConfigProvider for external accounts.
|
||||||
|
func NewExternalAccountConfigProvider(audience, inputUniverseDomain string) (ConfigProvider, error) {
|
||||||
|
var audienceDomain, projectNumber, poolID string
|
||||||
|
var isWorkload bool
|
||||||
|
|
||||||
|
matches := workloadAudiencePattern.FindStringSubmatch(audience)
|
||||||
|
if len(matches) == 4 { // Expecting full match, domain, projectNumber, poolID
|
||||||
|
audienceDomain = matches[1]
|
||||||
|
projectNumber = matches[2]
|
||||||
|
poolID = matches[3]
|
||||||
|
isWorkload = true
|
||||||
|
} else {
|
||||||
|
matches = workforceAudiencePattern.FindStringSubmatch(audience)
|
||||||
|
if len(matches) == 3 { // Expecting full match, domain, poolID
|
||||||
|
audienceDomain = matches[1]
|
||||||
|
poolID = matches[2]
|
||||||
|
isWorkload = false
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("trustboundary: unknown audience format: %q", audience)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
effectiveUniverseDomain := inputUniverseDomain
|
||||||
|
if effectiveUniverseDomain == "" {
|
||||||
|
effectiveUniverseDomain = audienceDomain
|
||||||
|
} else if audienceDomain != "" && effectiveUniverseDomain != audienceDomain {
|
||||||
|
return nil, fmt.Errorf("trustboundary: provided universe domain (%q) does not match domain in audience (%q)", inputUniverseDomain, audienceDomain)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isWorkload {
|
||||||
|
return &workloadIdentityPoolConfigProvider{
|
||||||
|
projectNumber: projectNumber,
|
||||||
|
poolID: poolID,
|
||||||
|
universeDomain: effectiveUniverseDomain,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return &workforcePoolConfigProvider{
|
||||||
|
poolID: poolID,
|
||||||
|
universeDomain: effectiveUniverseDomain,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type workforcePoolConfigProvider struct {
|
||||||
|
poolID string
|
||||||
|
universeDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *workforcePoolConfigProvider) GetTrustBoundaryEndpoint(ctx context.Context) (string, error) {
|
||||||
|
return fmt.Sprintf(workforceAllowedLocationsEndpoint, p.universeDomain, p.poolID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *workforcePoolConfigProvider) GetUniverseDomain(ctx context.Context) (string, error) {
|
||||||
|
return p.universeDomain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type workloadIdentityPoolConfigProvider struct {
|
||||||
|
projectNumber string
|
||||||
|
poolID string
|
||||||
|
universeDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *workloadIdentityPoolConfigProvider) GetTrustBoundaryEndpoint(ctx context.Context) (string, error) {
|
||||||
|
return fmt.Sprintf(workloadAllowedLocationsEndpoint, p.universeDomain, p.projectNumber, p.poolID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *workloadIdentityPoolConfigProvider) GetUniverseDomain(ctx context.Context) (string, error) {
|
||||||
|
return p.universeDomain, nil
|
||||||
|
}
|
||||||
392
vendor/cloud.google.com/go/auth/internal/trustboundary/trust_boundary.go
generated
vendored
Normal file
392
vendor/cloud.google.com/go/auth/internal/trustboundary/trust_boundary.go
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
// Copyright 2025 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 trustboundary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"cloud.google.com/go/auth/internal/retry"
|
||||||
|
"cloud.google.com/go/auth/internal/transport/headers"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// serviceAccountAllowedLocationsEndpoint is the URL for fetching allowed locations for a given service account email.
|
||||||
|
serviceAccountAllowedLocationsEndpoint = "https://iamcredentials.%s/v1/projects/-/serviceAccounts/%s/allowedLocations"
|
||||||
|
)
|
||||||
|
|
||||||
|
// isEnabled wraps isTrustBoundaryEnabled with sync.OnceValues to ensure it's
|
||||||
|
// called only once.
|
||||||
|
var isEnabled = sync.OnceValues(isTrustBoundaryEnabled)
|
||||||
|
|
||||||
|
// IsEnabled returns if the trust boundary feature is enabled and an error if
|
||||||
|
// the configuration is invalid. The underlying check is performed only once.
|
||||||
|
func IsEnabled() (bool, error) {
|
||||||
|
return isEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isTrustBoundaryEnabled checks if the trust boundary feature is enabled via
|
||||||
|
// GOOGLE_AUTH_TRUST_BOUNDARY_ENABLED environment variable.
|
||||||
|
//
|
||||||
|
// If the environment variable is not set, it is considered false.
|
||||||
|
//
|
||||||
|
// The environment variable is interpreted as a boolean with the following
|
||||||
|
// (case-insensitive) rules:
|
||||||
|
// - "true", "1" are considered true.
|
||||||
|
// - "false", "0" are considered false.
|
||||||
|
//
|
||||||
|
// Any other values will return an error.
|
||||||
|
func isTrustBoundaryEnabled() (bool, error) {
|
||||||
|
const envVar = "GOOGLE_AUTH_TRUST_BOUNDARY_ENABLED"
|
||||||
|
val, ok := os.LookupEnv(envVar)
|
||||||
|
if !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
val = strings.ToLower(val)
|
||||||
|
switch val {
|
||||||
|
case "true", "1":
|
||||||
|
return true, nil
|
||||||
|
case "false", "0":
|
||||||
|
return false, nil
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf(`invalid value for %s: %q. Must be one of "true", "false", "1", or "0"`, envVar, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigProvider provides specific configuration for trust boundary lookups.
|
||||||
|
type ConfigProvider interface {
|
||||||
|
// GetTrustBoundaryEndpoint returns the endpoint URL for the trust boundary lookup.
|
||||||
|
GetTrustBoundaryEndpoint(ctx context.Context) (url string, err error)
|
||||||
|
// GetUniverseDomain returns the universe domain associated with the credential.
|
||||||
|
// It may return an error if the universe domain cannot be determined.
|
||||||
|
GetUniverseDomain(ctx context.Context) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowedLocationsResponse is the structure of the response from the Trust Boundary API.
|
||||||
|
type AllowedLocationsResponse struct {
|
||||||
|
// Locations is the list of allowed locations.
|
||||||
|
Locations []string `json:"locations"`
|
||||||
|
// EncodedLocations is the encoded representation of the allowed locations.
|
||||||
|
EncodedLocations string `json:"encodedLocations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchTrustBoundaryData fetches the trust boundary data from the API.
|
||||||
|
func fetchTrustBoundaryData(ctx context.Context, client *http.Client, url string, token *auth.Token, logger *slog.Logger) (*internal.TrustBoundaryData, error) {
|
||||||
|
if logger == nil {
|
||||||
|
logger = slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||||
|
}
|
||||||
|
if client == nil {
|
||||||
|
return nil, errors.New("trustboundary: HTTP client is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if url == "" {
|
||||||
|
return nil, errors.New("trustboundary: URL cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: failed to create trust boundary request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if token == nil || token.Value == "" {
|
||||||
|
return nil, errors.New("trustboundary: access token required for lookup API authentication")
|
||||||
|
}
|
||||||
|
headers.SetAuthHeader(token, req)
|
||||||
|
logger.DebugContext(ctx, "trust boundary request", "request", internallog.HTTPRequest(req, nil))
|
||||||
|
|
||||||
|
retryer := retry.New()
|
||||||
|
var response *http.Response
|
||||||
|
for {
|
||||||
|
response, err = client.Do(req)
|
||||||
|
|
||||||
|
var statusCode int
|
||||||
|
if response != nil {
|
||||||
|
statusCode = response.StatusCode
|
||||||
|
}
|
||||||
|
pause, shouldRetry := retryer.Retry(statusCode, err)
|
||||||
|
|
||||||
|
if !shouldRetry {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if response != nil {
|
||||||
|
// Drain and close the body to reuse the connection
|
||||||
|
io.Copy(io.Discard, response.Body)
|
||||||
|
response.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := retry.Sleep(ctx, pause); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: failed to fetch trust boundary: %w", err)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: failed to read trust boundary response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.DebugContext(ctx, "trust boundary response", "response", internallog.HTTPResponse(response, body))
|
||||||
|
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("trustboundary: trust boundary request failed with status: %s, body: %s", response.Status, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
apiResponse := AllowedLocationsResponse{}
|
||||||
|
if err := json.Unmarshal(body, &apiResponse); err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: failed to unmarshal trust boundary response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiResponse.EncodedLocations == "" {
|
||||||
|
return nil, errors.New("trustboundary: invalid API response: encodedLocations is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal.NewTrustBoundaryData(apiResponse.Locations, apiResponse.EncodedLocations), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceAccountConfig holds configuration for SA trust boundary lookups.
|
||||||
|
// It implements the ConfigProvider interface.
|
||||||
|
type serviceAccountConfig struct {
|
||||||
|
ServiceAccountEmail string
|
||||||
|
UniverseDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServiceAccountConfigProvider creates a new config for service accounts.
|
||||||
|
func NewServiceAccountConfigProvider(saEmail, universeDomain string) ConfigProvider {
|
||||||
|
return &serviceAccountConfig{
|
||||||
|
ServiceAccountEmail: saEmail,
|
||||||
|
UniverseDomain: universeDomain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrustBoundaryEndpoint returns the formatted URL for fetching allowed locations
|
||||||
|
// for the configured service account and universe domain.
|
||||||
|
func (sac *serviceAccountConfig) GetTrustBoundaryEndpoint(ctx context.Context) (url string, err error) {
|
||||||
|
if sac.ServiceAccountEmail == "" {
|
||||||
|
return "", errors.New("trustboundary: service account email cannot be empty for config")
|
||||||
|
}
|
||||||
|
ud := sac.UniverseDomain
|
||||||
|
if ud == "" {
|
||||||
|
ud = internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(serviceAccountAllowedLocationsEndpoint, ud, sac.ServiceAccountEmail), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUniverseDomain returns the configured universe domain, defaulting to
|
||||||
|
// [internal.DefaultUniverseDomain] if not explicitly set.
|
||||||
|
func (sac *serviceAccountConfig) GetUniverseDomain(ctx context.Context) (string, error) {
|
||||||
|
if sac.UniverseDomain == "" {
|
||||||
|
return internal.DefaultUniverseDomain, nil
|
||||||
|
}
|
||||||
|
return sac.UniverseDomain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataProvider fetches and caches trust boundary Data.
|
||||||
|
// It implements the DataProvider interface and uses a ConfigProvider
|
||||||
|
// to get type-specific details for the lookup.
|
||||||
|
type DataProvider struct {
|
||||||
|
client *http.Client
|
||||||
|
configProvider ConfigProvider
|
||||||
|
data *internal.TrustBoundaryData
|
||||||
|
logger *slog.Logger
|
||||||
|
base auth.TokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider wraps the provided base [auth.TokenProvider] to create a new
|
||||||
|
// provider that injects tokens with trust boundary data. It uses the provided
|
||||||
|
// HTTP client and configProvider to fetch the data and attach it to the token's
|
||||||
|
// metadata.
|
||||||
|
func NewProvider(client *http.Client, configProvider ConfigProvider, logger *slog.Logger, base auth.TokenProvider) (*DataProvider, error) {
|
||||||
|
if client == nil {
|
||||||
|
return nil, errors.New("trustboundary: HTTP client cannot be nil for DataProvider")
|
||||||
|
}
|
||||||
|
if configProvider == nil {
|
||||||
|
return nil, errors.New("trustboundary: ConfigProvider cannot be nil for DataProvider")
|
||||||
|
}
|
||||||
|
p := &DataProvider{
|
||||||
|
client: client,
|
||||||
|
configProvider: configProvider,
|
||||||
|
logger: internallog.New(logger),
|
||||||
|
base: base,
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token retrieves a token from the base provider and injects it with trust
|
||||||
|
// boundary data.
|
||||||
|
func (p *DataProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||||
|
// Get the original token.
|
||||||
|
token, err := p.base.Token(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tbData, err := p.GetTrustBoundaryData(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: error fetching the trust boundary data: %w", err)
|
||||||
|
}
|
||||||
|
if tbData != nil {
|
||||||
|
if token.Metadata == nil {
|
||||||
|
token.Metadata = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
token.Metadata[internal.TrustBoundaryDataKey] = *tbData
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrustBoundaryData retrieves the trust boundary data.
|
||||||
|
// It first checks the universe domain: if it's non-default, a NoOp is returned.
|
||||||
|
// Otherwise, it checks a local cache. If the data is not cached as NoOp,
|
||||||
|
// it fetches new data from the endpoint provided by its ConfigProvider,
|
||||||
|
// using the given accessToken for authentication. Results are cached.
|
||||||
|
// If fetching fails, it returns previously cached data if available, otherwise the fetch error.
|
||||||
|
func (p *DataProvider) GetTrustBoundaryData(ctx context.Context, token *auth.Token) (*internal.TrustBoundaryData, error) {
|
||||||
|
// Check the universe domain.
|
||||||
|
uniDomain, err := p.configProvider.GetUniverseDomain(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: error getting universe domain: %w", err)
|
||||||
|
}
|
||||||
|
if uniDomain != "" && uniDomain != internal.DefaultUniverseDomain {
|
||||||
|
if p.data == nil || p.data.EncodedLocations != internal.TrustBoundaryNoOp {
|
||||||
|
p.data = internal.NewNoOpTrustBoundaryData()
|
||||||
|
}
|
||||||
|
return p.data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check cache for a no-op result from a previous API call.
|
||||||
|
cachedData := p.data
|
||||||
|
if cachedData != nil && cachedData.EncodedLocations == internal.TrustBoundaryNoOp {
|
||||||
|
return cachedData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the endpoint
|
||||||
|
url, err := p.configProvider.GetTrustBoundaryEndpoint(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trustboundary: error getting the lookup endpoint: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed to fetch new data.
|
||||||
|
newData, fetchErr := fetchTrustBoundaryData(ctx, p.client, url, token, p.logger)
|
||||||
|
|
||||||
|
if fetchErr != nil {
|
||||||
|
// Fetch failed. Fallback to cachedData if available.
|
||||||
|
if cachedData != nil {
|
||||||
|
return cachedData, nil // Successful fallback
|
||||||
|
}
|
||||||
|
// No cache to fallback to.
|
||||||
|
return nil, fmt.Errorf("trustboundary: failed to fetch trust boundary data for endpoint %s and no cache available: %w", url, fetchErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch successful. Update cache.
|
||||||
|
p.data = newData
|
||||||
|
return newData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCEConfigProvider implements ConfigProvider for GCE environments.
|
||||||
|
// It lazily fetches and caches the necessary metadata (service account email, universe domain)
|
||||||
|
// from the GCE metadata server.
|
||||||
|
type GCEConfigProvider struct {
|
||||||
|
// universeDomainProvider provides the universe domain and underlying metadata client.
|
||||||
|
universeDomainProvider *internal.ComputeUniverseDomainProvider
|
||||||
|
|
||||||
|
// Caching for service account email
|
||||||
|
saOnce sync.Once
|
||||||
|
saEmail string
|
||||||
|
saEmailErr error
|
||||||
|
|
||||||
|
// Caching for universe domain
|
||||||
|
udOnce sync.Once
|
||||||
|
ud string
|
||||||
|
udErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGCEConfigProvider creates a new GCEConfigProvider
|
||||||
|
// which uses the provided gceUDP to interact with the GCE metadata server.
|
||||||
|
func NewGCEConfigProvider(gceUDP *internal.ComputeUniverseDomainProvider) *GCEConfigProvider {
|
||||||
|
// The validity of gceUDP and its internal MetadataClient will be checked
|
||||||
|
// within the GetTrustBoundaryEndpoint and GetUniverseDomain methods.
|
||||||
|
return &GCEConfigProvider{
|
||||||
|
universeDomainProvider: gceUDP,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GCEConfigProvider) fetchSA(ctx context.Context) {
|
||||||
|
if g.universeDomainProvider == nil || g.universeDomainProvider.MetadataClient == nil {
|
||||||
|
g.saEmailErr = errors.New("trustboundary: GCEConfigProvider not properly initialized (missing ComputeUniverseDomainProvider or MetadataClient)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mdClient := g.universeDomainProvider.MetadataClient
|
||||||
|
saEmail, err := mdClient.EmailWithContext(ctx, "default")
|
||||||
|
if err != nil {
|
||||||
|
g.saEmailErr = fmt.Errorf("trustboundary: GCE config: failed to get service account email: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.saEmail = saEmail
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GCEConfigProvider) fetchUD(ctx context.Context) {
|
||||||
|
if g.universeDomainProvider == nil || g.universeDomainProvider.MetadataClient == nil {
|
||||||
|
g.udErr = errors.New("trustboundary: GCEConfigProvider not properly initialized (missing ComputeUniverseDomainProvider or MetadataClient)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ud, err := g.universeDomainProvider.GetProperty(ctx)
|
||||||
|
if err != nil {
|
||||||
|
g.udErr = fmt.Errorf("trustboundary: GCE config: failed to get universe domain: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ud == "" {
|
||||||
|
ud = internal.DefaultUniverseDomain
|
||||||
|
}
|
||||||
|
g.ud = ud
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrustBoundaryEndpoint constructs the trust boundary lookup URL for a GCE environment.
|
||||||
|
// It uses cached metadata (service account email, universe domain) after the first call.
|
||||||
|
func (g *GCEConfigProvider) GetTrustBoundaryEndpoint(ctx context.Context) (string, error) {
|
||||||
|
g.saOnce.Do(func() { g.fetchSA(ctx) })
|
||||||
|
if g.saEmailErr != nil {
|
||||||
|
return "", g.saEmailErr
|
||||||
|
}
|
||||||
|
g.udOnce.Do(func() { g.fetchUD(ctx) })
|
||||||
|
if g.udErr != nil {
|
||||||
|
return "", g.udErr
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(serviceAccountAllowedLocationsEndpoint, g.ud, g.saEmail), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUniverseDomain retrieves the universe domain from the GCE metadata server.
|
||||||
|
// It uses a cached value after the first call.
|
||||||
|
func (g *GCEConfigProvider) GetUniverseDomain(ctx context.Context) (string, error) {
|
||||||
|
g.udOnce.Do(func() { g.fetchUD(ctx) })
|
||||||
|
if g.udErr != nil {
|
||||||
|
return "", g.udErr
|
||||||
|
}
|
||||||
|
return g.ud, nil
|
||||||
|
}
|
||||||
20
vendor/cloud.google.com/go/auth/internal/version.go
generated
vendored
Normal file
20
vendor/cloud.google.com/go/auth/internal/version.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2026 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.
|
||||||
|
|
||||||
|
// Code generated by gapicgen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
// Version is the current tagged release of the library.
|
||||||
|
const Version = "0.18.1"
|
||||||
82
vendor/cloud.google.com/go/auth/oauth2adapt/CHANGES.md
generated
vendored
Normal file
82
vendor/cloud.google.com/go/auth/oauth2adapt/CHANGES.md
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [0.2.8](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.7...auth/oauth2adapt/v0.2.8) (2025-03-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update golang.org/x/net to 0.37.0 ([1144978](https://github.com/googleapis/google-cloud-go/commit/11449782c7fb4896bf8b8b9cde8e7441c84fb2fd))
|
||||||
|
|
||||||
|
## [0.2.7](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.6...auth/oauth2adapt/v0.2.7) (2025-01-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
||||||
|
|
||||||
|
## [0.2.6](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.5...auth/oauth2adapt/v0.2.6) (2024-11-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Copy map in tokenSourceAdapter.Token ([#11164](https://github.com/googleapis/google-cloud-go/issues/11164)) ([8cb0cbc](https://github.com/googleapis/google-cloud-go/commit/8cb0cbccdc32886dfb3af49fee04012937d114d2)), refs [#11161](https://github.com/googleapis/google-cloud-go/issues/11161)
|
||||||
|
|
||||||
|
## [0.2.5](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.4...auth/oauth2adapt/v0.2.5) (2024-10-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Convert token metadata where possible ([#11062](https://github.com/googleapis/google-cloud-go/issues/11062)) ([34bf1c1](https://github.com/googleapis/google-cloud-go/commit/34bf1c164465d66745c0cfdf7cd10a8e2da92e52))
|
||||||
|
|
||||||
|
## [0.2.4](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.3...auth/oauth2adapt/v0.2.4) (2024-08-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
|
||||||
|
## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.2...auth/oauth2adapt/v0.2.3) (2024-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Bump google.golang.org/api@v0.187.0 ([8fa9e39](https://github.com/googleapis/google-cloud-go/commit/8fa9e398e512fd8533fd49060371e61b5725a85b))
|
||||||
|
|
||||||
|
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.1...auth/oauth2adapt/v0.2.2) (2024-04-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Bump x/net to v0.24.0 ([ba31ed5](https://github.com/googleapis/google-cloud-go/commit/ba31ed5fda2c9664f2e1cf972469295e63deb5b4))
|
||||||
|
|
||||||
|
## [0.2.1](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.0...auth/oauth2adapt/v0.2.1) (2024-04-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Adapt Token Types to be translated ([#9801](https://github.com/googleapis/google-cloud-go/issues/9801)) ([70f4115](https://github.com/googleapis/google-cloud-go/commit/70f411555ebbf2b71e6d425cc8d2030644c6b438)), refs [#9800](https://github.com/googleapis/google-cloud-go/issues/9800)
|
||||||
|
|
||||||
|
## [0.2.0](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.1.0...auth/oauth2adapt/v0.2.0) (2024-04-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Add helpers for working with credentials types ([#9694](https://github.com/googleapis/google-cloud-go/issues/9694)) ([cf33b55](https://github.com/googleapis/google-cloud-go/commit/cf33b5514423a2ac5c2a323a1cd99aac34fd4233))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update protobuf dep to v1.33.0 ([30b038d](https://github.com/googleapis/google-cloud-go/commit/30b038d8cac0b8cd5dd4761c87f3f298760dd33a))
|
||||||
|
|
||||||
|
## 0.1.0 (2023-10-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Adds a new module to translate types ([#8595](https://github.com/googleapis/google-cloud-go/issues/8595)) ([6933c5a](https://github.com/googleapis/google-cloud-go/commit/6933c5a0c1fc8e58cbfff8bbca439d671b94672f))
|
||||||
|
* **auth/oauth2adapt:** Fixup deps for release ([#8747](https://github.com/googleapis/google-cloud-go/issues/8747)) ([749d243](https://github.com/googleapis/google-cloud-go/commit/749d243862b025a6487a4d2d339219889b4cfe70))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update golang.org/x/net to v0.17.0 ([174da47](https://github.com/googleapis/google-cloud-go/commit/174da47254fefb12921bbfc65b7829a453af6f5d))
|
||||||
202
vendor/cloud.google.com/go/auth/oauth2adapt/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/auth/oauth2adapt/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.
|
||||||
200
vendor/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go
generated
vendored
Normal file
200
vendor/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
// Copyright 2023 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 oauth2adapt helps converts types used in [cloud.google.com/go/auth]
|
||||||
|
// and [golang.org/x/oauth2].
|
||||||
|
package oauth2adapt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/google"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
oauth2TokenSourceKey = "oauth2.google.tokenSource"
|
||||||
|
oauth2ServiceAccountKey = "oauth2.google.serviceAccount"
|
||||||
|
authTokenSourceKey = "auth.google.tokenSource"
|
||||||
|
authServiceAccountKey = "auth.google.serviceAccount"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenProviderFromTokenSource converts any [golang.org/x/oauth2.TokenSource]
|
||||||
|
// into a [cloud.google.com/go/auth.TokenProvider].
|
||||||
|
func TokenProviderFromTokenSource(ts oauth2.TokenSource) auth.TokenProvider {
|
||||||
|
return &tokenProviderAdapter{ts: ts}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenProviderAdapter struct {
|
||||||
|
ts oauth2.TokenSource
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token fulfills the [cloud.google.com/go/auth.TokenProvider] interface. It
|
||||||
|
// is a light wrapper around the underlying TokenSource.
|
||||||
|
func (tp *tokenProviderAdapter) Token(context.Context) (*auth.Token, error) {
|
||||||
|
tok, err := tp.ts.Token()
|
||||||
|
if err != nil {
|
||||||
|
var err2 *oauth2.RetrieveError
|
||||||
|
if ok := errors.As(err, &err2); ok {
|
||||||
|
return nil, AuthErrorFromRetrieveError(err2)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Preserve compute token metadata, for both types of tokens.
|
||||||
|
metadata := map[string]interface{}{}
|
||||||
|
if val, ok := tok.Extra(oauth2TokenSourceKey).(string); ok {
|
||||||
|
metadata[authTokenSourceKey] = val
|
||||||
|
metadata[oauth2TokenSourceKey] = val
|
||||||
|
}
|
||||||
|
if val, ok := tok.Extra(oauth2ServiceAccountKey).(string); ok {
|
||||||
|
metadata[authServiceAccountKey] = val
|
||||||
|
metadata[oauth2ServiceAccountKey] = val
|
||||||
|
}
|
||||||
|
return &auth.Token{
|
||||||
|
Value: tok.AccessToken,
|
||||||
|
Type: tok.Type(),
|
||||||
|
Expiry: tok.Expiry,
|
||||||
|
Metadata: metadata,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenSourceFromTokenProvider converts any
|
||||||
|
// [cloud.google.com/go/auth.TokenProvider] into a
|
||||||
|
// [golang.org/x/oauth2.TokenSource].
|
||||||
|
func TokenSourceFromTokenProvider(tp auth.TokenProvider) oauth2.TokenSource {
|
||||||
|
return &tokenSourceAdapter{tp: tp}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenSourceAdapter struct {
|
||||||
|
tp auth.TokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token fulfills the [golang.org/x/oauth2.TokenSource] interface. It
|
||||||
|
// is a light wrapper around the underlying TokenProvider.
|
||||||
|
func (ts *tokenSourceAdapter) Token() (*oauth2.Token, error) {
|
||||||
|
tok, err := ts.tp.Token(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
var err2 *auth.Error
|
||||||
|
if ok := errors.As(err, &err2); ok {
|
||||||
|
return nil, AddRetrieveErrorToAuthError(err2)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tok2 := &oauth2.Token{
|
||||||
|
AccessToken: tok.Value,
|
||||||
|
TokenType: tok.Type,
|
||||||
|
Expiry: tok.Expiry,
|
||||||
|
}
|
||||||
|
// Preserve token metadata.
|
||||||
|
m := tok.Metadata
|
||||||
|
if m != nil {
|
||||||
|
// Copy map to avoid concurrent map writes error (#11161).
|
||||||
|
metadata := make(map[string]interface{}, len(m)+2)
|
||||||
|
for k, v := range m {
|
||||||
|
metadata[k] = v
|
||||||
|
}
|
||||||
|
// Append compute token metadata in converted form.
|
||||||
|
if val, ok := metadata[authTokenSourceKey].(string); ok && val != "" {
|
||||||
|
metadata[oauth2TokenSourceKey] = val
|
||||||
|
}
|
||||||
|
if val, ok := metadata[authServiceAccountKey].(string); ok && val != "" {
|
||||||
|
metadata[oauth2ServiceAccountKey] = val
|
||||||
|
}
|
||||||
|
tok2 = tok2.WithExtra(metadata)
|
||||||
|
}
|
||||||
|
return tok2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthCredentialsFromOauth2Credentials converts a [golang.org/x/oauth2/google.Credentials]
|
||||||
|
// to a [cloud.google.com/go/auth.Credentials].
|
||||||
|
func AuthCredentialsFromOauth2Credentials(creds *google.Credentials) *auth.Credentials {
|
||||||
|
if creds == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return auth.NewCredentials(&auth.CredentialsOptions{
|
||||||
|
TokenProvider: TokenProviderFromTokenSource(creds.TokenSource),
|
||||||
|
JSON: creds.JSON,
|
||||||
|
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
||||||
|
return creds.ProjectID, nil
|
||||||
|
}),
|
||||||
|
UniverseDomainProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
||||||
|
return creds.GetUniverseDomain()
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Oauth2CredentialsFromAuthCredentials converts a [cloud.google.com/go/auth.Credentials]
|
||||||
|
// to a [golang.org/x/oauth2/google.Credentials].
|
||||||
|
func Oauth2CredentialsFromAuthCredentials(creds *auth.Credentials) *google.Credentials {
|
||||||
|
if creds == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Throw away errors as old credentials are not request aware. Also, no
|
||||||
|
// network requests are currently happening for this use case.
|
||||||
|
projectID, _ := creds.ProjectID(context.Background())
|
||||||
|
|
||||||
|
return &google.Credentials{
|
||||||
|
TokenSource: TokenSourceFromTokenProvider(creds.TokenProvider),
|
||||||
|
ProjectID: projectID,
|
||||||
|
JSON: creds.JSON(),
|
||||||
|
UniverseDomainProvider: func() (string, error) {
|
||||||
|
return creds.UniverseDomain(context.Background())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type oauth2Error struct {
|
||||||
|
ErrorCode string `json:"error"`
|
||||||
|
ErrorDescription string `json:"error_description"`
|
||||||
|
ErrorURI string `json:"error_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRetrieveErrorToAuthError returns the same error provided and adds a
|
||||||
|
// [golang.org/x/oauth2.RetrieveError] to the error chain by setting the `Err` field on the
|
||||||
|
// [cloud.google.com/go/auth.Error].
|
||||||
|
func AddRetrieveErrorToAuthError(err *auth.Error) *auth.Error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e := &oauth2.RetrieveError{
|
||||||
|
Response: err.Response,
|
||||||
|
Body: err.Body,
|
||||||
|
}
|
||||||
|
err.Err = e
|
||||||
|
if len(err.Body) > 0 {
|
||||||
|
var oErr oauth2Error
|
||||||
|
// ignore the error as it only fills in extra details
|
||||||
|
json.Unmarshal(err.Body, &oErr)
|
||||||
|
e.ErrorCode = oErr.ErrorCode
|
||||||
|
e.ErrorDescription = oErr.ErrorDescription
|
||||||
|
e.ErrorURI = oErr.ErrorURI
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthErrorFromRetrieveError returns an [cloud.google.com/go/auth.Error] that
|
||||||
|
// wraps the provided [golang.org/x/oauth2.RetrieveError].
|
||||||
|
func AuthErrorFromRetrieveError(err *oauth2.RetrieveError) *auth.Error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &auth.Error{
|
||||||
|
Response: err.Response,
|
||||||
|
Body: err.Body,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
382
vendor/cloud.google.com/go/auth/threelegged.go
generated
vendored
Normal file
382
vendor/cloud.google.com/go/auth/threelegged.go
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
// Copyright 2023 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 auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/auth/internal"
|
||||||
|
"github.com/googleapis/gax-go/v2/internallog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// Options3LO are the options for doing a 3-legged OAuth2 flow.
|
||||||
|
type Options3LO struct {
|
||||||
|
// ClientID is the application's ID.
|
||||||
|
ClientID string
|
||||||
|
// ClientSecret is the application's secret. Not required if AuthHandlerOpts
|
||||||
|
// is set.
|
||||||
|
ClientSecret string
|
||||||
|
// AuthURL is the URL for authenticating.
|
||||||
|
AuthURL string
|
||||||
|
// TokenURL is the URL for retrieving a token.
|
||||||
|
TokenURL string
|
||||||
|
// AuthStyle is used to describe how to client info in the token request.
|
||||||
|
AuthStyle Style
|
||||||
|
// RefreshToken is the token used to refresh the credential. Not required
|
||||||
|
// if AuthHandlerOpts is set.
|
||||||
|
RefreshToken string
|
||||||
|
// RedirectURL is the URL to redirect users to. Optional.
|
||||||
|
RedirectURL string
|
||||||
|
// Scopes specifies requested permissions for the Token. Optional.
|
||||||
|
Scopes []string
|
||||||
|
|
||||||
|
// URLParams are the set of values to apply to the token exchange. Optional.
|
||||||
|
URLParams url.Values
|
||||||
|
// Client is the client to be used to make the underlying token requests.
|
||||||
|
// Optional.
|
||||||
|
Client *http.Client
|
||||||
|
// EarlyTokenExpiry is the time before the token expires that it should be
|
||||||
|
// refreshed. If not set the default value is 3 minutes and 45 seconds.
|
||||||
|
// Optional.
|
||||||
|
EarlyTokenExpiry time.Duration
|
||||||
|
|
||||||
|
// AuthHandlerOpts provides a set of options for doing a
|
||||||
|
// 3-legged OAuth2 flow with a custom [AuthorizationHandler]. Optional.
|
||||||
|
AuthHandlerOpts *AuthorizationHandlerOptions
|
||||||
|
// Logger is used for debug logging. If provided, logging will be enabled
|
||||||
|
// at the loggers configured level. By default logging is disabled unless
|
||||||
|
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||||
|
// logger will be used. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options3LO) validate() error {
|
||||||
|
if o == nil {
|
||||||
|
return errors.New("auth: options must be provided")
|
||||||
|
}
|
||||||
|
if o.ClientID == "" {
|
||||||
|
return errors.New("auth: client ID must be provided")
|
||||||
|
}
|
||||||
|
if o.AuthHandlerOpts == nil && o.ClientSecret == "" {
|
||||||
|
return errors.New("auth: client secret must be provided")
|
||||||
|
}
|
||||||
|
if o.AuthURL == "" {
|
||||||
|
return errors.New("auth: auth URL must be provided")
|
||||||
|
}
|
||||||
|
if o.TokenURL == "" {
|
||||||
|
return errors.New("auth: token URL must be provided")
|
||||||
|
}
|
||||||
|
if o.AuthStyle == StyleUnknown {
|
||||||
|
return errors.New("auth: auth style must be provided")
|
||||||
|
}
|
||||||
|
if o.AuthHandlerOpts == nil && o.RefreshToken == "" {
|
||||||
|
return errors.New("auth: refresh token must be provided")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options3LO) logger() *slog.Logger {
|
||||||
|
return internallog.New(o.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PKCEOptions holds parameters to support PKCE.
|
||||||
|
type PKCEOptions struct {
|
||||||
|
// Challenge is the un-padded, base64-url-encoded string of the encrypted code verifier.
|
||||||
|
Challenge string // The un-padded, base64-url-encoded string of the encrypted code verifier.
|
||||||
|
// ChallengeMethod is the encryption method (ex. S256).
|
||||||
|
ChallengeMethod string
|
||||||
|
// Verifier is the original, non-encrypted secret.
|
||||||
|
Verifier string // The original, non-encrypted secret.
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenJSON struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
// error fields
|
||||||
|
ErrorCode string `json:"error"`
|
||||||
|
ErrorDescription string `json:"error_description"`
|
||||||
|
ErrorURI string `json:"error_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *tokenJSON) expiry() (t time.Time) {
|
||||||
|
if v := e.ExpiresIn; v != 0 {
|
||||||
|
return time.Now().Add(time.Duration(v) * time.Second)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options3LO) client() *http.Client {
|
||||||
|
if o.Client != nil {
|
||||||
|
return o.Client
|
||||||
|
}
|
||||||
|
return internal.DefaultClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
// authCodeURL returns a URL that points to a OAuth2 consent page.
|
||||||
|
func (o *Options3LO) authCodeURL(state string, values url.Values) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(o.AuthURL)
|
||||||
|
v := url.Values{
|
||||||
|
"response_type": {"code"},
|
||||||
|
"client_id": {o.ClientID},
|
||||||
|
}
|
||||||
|
if o.RedirectURL != "" {
|
||||||
|
v.Set("redirect_uri", o.RedirectURL)
|
||||||
|
}
|
||||||
|
if len(o.Scopes) > 0 {
|
||||||
|
v.Set("scope", strings.Join(o.Scopes, " "))
|
||||||
|
}
|
||||||
|
if state != "" {
|
||||||
|
v.Set("state", state)
|
||||||
|
}
|
||||||
|
if o.AuthHandlerOpts != nil {
|
||||||
|
if o.AuthHandlerOpts.PKCEOpts != nil &&
|
||||||
|
o.AuthHandlerOpts.PKCEOpts.Challenge != "" {
|
||||||
|
v.Set(codeChallengeKey, o.AuthHandlerOpts.PKCEOpts.Challenge)
|
||||||
|
}
|
||||||
|
if o.AuthHandlerOpts.PKCEOpts != nil &&
|
||||||
|
o.AuthHandlerOpts.PKCEOpts.ChallengeMethod != "" {
|
||||||
|
v.Set(codeChallengeMethodKey, o.AuthHandlerOpts.PKCEOpts.ChallengeMethod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k := range values {
|
||||||
|
v.Set(k, v.Get(k))
|
||||||
|
}
|
||||||
|
if strings.Contains(o.AuthURL, "?") {
|
||||||
|
buf.WriteByte('&')
|
||||||
|
} else {
|
||||||
|
buf.WriteByte('?')
|
||||||
|
}
|
||||||
|
buf.WriteString(v.Encode())
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// New3LOTokenProvider returns a [TokenProvider] based on the 3-legged OAuth2
|
||||||
|
// configuration. The TokenProvider is caches and auto-refreshes tokens by
|
||||||
|
// default.
|
||||||
|
func New3LOTokenProvider(opts *Options3LO) (TokenProvider, error) {
|
||||||
|
if err := opts.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if opts.AuthHandlerOpts != nil {
|
||||||
|
return new3LOTokenProviderWithAuthHandler(opts), nil
|
||||||
|
}
|
||||||
|
return NewCachedTokenProvider(&tokenProvider3LO{opts: opts, refreshToken: opts.RefreshToken, client: opts.client()}, &CachedTokenProviderOptions{
|
||||||
|
ExpireEarly: opts.EarlyTokenExpiry,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizationHandlerOptions provides a set of options to specify for doing a
|
||||||
|
// 3-legged OAuth2 flow with a custom [AuthorizationHandler].
|
||||||
|
type AuthorizationHandlerOptions struct {
|
||||||
|
// AuthorizationHandler specifies the handler used to for the authorization
|
||||||
|
// part of the flow.
|
||||||
|
Handler AuthorizationHandler
|
||||||
|
// State is used verify that the "state" is identical in the request and
|
||||||
|
// response before exchanging the auth code for OAuth2 token.
|
||||||
|
State string
|
||||||
|
// PKCEOpts allows setting configurations for PKCE. Optional.
|
||||||
|
PKCEOpts *PKCEOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func new3LOTokenProviderWithAuthHandler(opts *Options3LO) TokenProvider {
|
||||||
|
return NewCachedTokenProvider(&tokenProviderWithHandler{opts: opts, state: opts.AuthHandlerOpts.State}, &CachedTokenProviderOptions{
|
||||||
|
ExpireEarly: opts.EarlyTokenExpiry,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// exchange handles the final exchange portion of the 3lo flow. Returns a Token,
|
||||||
|
// refreshToken, and error.
|
||||||
|
func (o *Options3LO) exchange(ctx context.Context, code string) (*Token, string, error) {
|
||||||
|
// Build request
|
||||||
|
v := url.Values{
|
||||||
|
"grant_type": {"authorization_code"},
|
||||||
|
"code": {code},
|
||||||
|
}
|
||||||
|
if o.RedirectURL != "" {
|
||||||
|
v.Set("redirect_uri", o.RedirectURL)
|
||||||
|
}
|
||||||
|
if o.AuthHandlerOpts != nil &&
|
||||||
|
o.AuthHandlerOpts.PKCEOpts != nil &&
|
||||||
|
o.AuthHandlerOpts.PKCEOpts.Verifier != "" {
|
||||||
|
v.Set(codeVerifierKey, o.AuthHandlerOpts.PKCEOpts.Verifier)
|
||||||
|
}
|
||||||
|
for k := range o.URLParams {
|
||||||
|
v.Set(k, o.URLParams.Get(k))
|
||||||
|
}
|
||||||
|
return fetchToken(ctx, o, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This struct is not safe for concurrent access alone, but the way it is used
|
||||||
|
// in this package by wrapping it with a cachedTokenProvider makes it so.
|
||||||
|
type tokenProvider3LO struct {
|
||||||
|
opts *Options3LO
|
||||||
|
client *http.Client
|
||||||
|
refreshToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *tokenProvider3LO) Token(ctx context.Context) (*Token, error) {
|
||||||
|
if tp.refreshToken == "" {
|
||||||
|
return nil, errors.New("auth: token expired and refresh token is not set")
|
||||||
|
}
|
||||||
|
v := url.Values{
|
||||||
|
"grant_type": {"refresh_token"},
|
||||||
|
"refresh_token": {tp.refreshToken},
|
||||||
|
}
|
||||||
|
for k := range tp.opts.URLParams {
|
||||||
|
v.Set(k, tp.opts.URLParams.Get(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
tk, rt, err := fetchToken(ctx, tp.opts, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if tp.refreshToken != rt && rt != "" {
|
||||||
|
tp.refreshToken = rt
|
||||||
|
}
|
||||||
|
return tk, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenProviderWithHandler struct {
|
||||||
|
opts *Options3LO
|
||||||
|
state string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp tokenProviderWithHandler) Token(ctx context.Context) (*Token, error) {
|
||||||
|
url := tp.opts.authCodeURL(tp.state, nil)
|
||||||
|
code, state, err := tp.opts.AuthHandlerOpts.Handler(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if state != tp.state {
|
||||||
|
return nil, errors.New("auth: state mismatch in 3-legged-OAuth flow")
|
||||||
|
}
|
||||||
|
tok, _, err := tp.opts.exchange(ctx, code)
|
||||||
|
return tok, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchToken returns a Token, refresh token, and/or an error.
|
||||||
|
func fetchToken(ctx context.Context, o *Options3LO, v url.Values) (*Token, string, error) {
|
||||||
|
var refreshToken string
|
||||||
|
if o.AuthStyle == StyleInParams {
|
||||||
|
if o.ClientID != "" {
|
||||||
|
v.Set("client_id", o.ClientID)
|
||||||
|
}
|
||||||
|
if o.ClientSecret != "" {
|
||||||
|
v.Set("client_secret", o.ClientSecret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", o.TokenURL, strings.NewReader(v.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, refreshToken, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
if o.AuthStyle == StyleInHeader {
|
||||||
|
req.SetBasicAuth(url.QueryEscape(o.ClientID), url.QueryEscape(o.ClientSecret))
|
||||||
|
}
|
||||||
|
logger := o.logger()
|
||||||
|
|
||||||
|
logger.DebugContext(ctx, "3LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||||
|
// Make request
|
||||||
|
resp, body, err := internal.DoRequest(o.client(), req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, refreshToken, err
|
||||||
|
}
|
||||||
|
logger.DebugContext(ctx, "3LO token response", "response", internallog.HTTPResponse(resp, body))
|
||||||
|
failureStatus := resp.StatusCode < 200 || resp.StatusCode > 299
|
||||||
|
tokError := &Error{
|
||||||
|
Response: resp,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
|
||||||
|
var token *Token
|
||||||
|
// errors ignored because of default switch on content
|
||||||
|
content, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||||
|
switch content {
|
||||||
|
case "application/x-www-form-urlencoded", "text/plain":
|
||||||
|
// some endpoints return a query string
|
||||||
|
vals, err := url.ParseQuery(string(body))
|
||||||
|
if err != nil {
|
||||||
|
if failureStatus {
|
||||||
|
return nil, refreshToken, tokError
|
||||||
|
}
|
||||||
|
return nil, refreshToken, fmt.Errorf("auth: cannot parse response: %w", err)
|
||||||
|
}
|
||||||
|
tokError.code = vals.Get("error")
|
||||||
|
tokError.description = vals.Get("error_description")
|
||||||
|
tokError.uri = vals.Get("error_uri")
|
||||||
|
token = &Token{
|
||||||
|
Value: vals.Get("access_token"),
|
||||||
|
Type: vals.Get("token_type"),
|
||||||
|
Metadata: make(map[string]interface{}, len(vals)),
|
||||||
|
}
|
||||||
|
for k, v := range vals {
|
||||||
|
token.Metadata[k] = v
|
||||||
|
}
|
||||||
|
refreshToken = vals.Get("refresh_token")
|
||||||
|
e := vals.Get("expires_in")
|
||||||
|
expires, _ := strconv.Atoi(e)
|
||||||
|
if expires != 0 {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
var tj tokenJSON
|
||||||
|
if err = json.Unmarshal(body, &tj); err != nil {
|
||||||
|
if failureStatus {
|
||||||
|
return nil, refreshToken, tokError
|
||||||
|
}
|
||||||
|
return nil, refreshToken, fmt.Errorf("auth: cannot parse json: %w", err)
|
||||||
|
}
|
||||||
|
tokError.code = tj.ErrorCode
|
||||||
|
tokError.description = tj.ErrorDescription
|
||||||
|
tokError.uri = tj.ErrorURI
|
||||||
|
token = &Token{
|
||||||
|
Value: tj.AccessToken,
|
||||||
|
Type: tj.TokenType,
|
||||||
|
Expiry: tj.expiry(),
|
||||||
|
Metadata: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
json.Unmarshal(body, &token.Metadata) // optional field, skip err check
|
||||||
|
refreshToken = tj.RefreshToken
|
||||||
|
}
|
||||||
|
// according to spec, servers should respond status 400 in error case
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc6749#section-5.2
|
||||||
|
// but some unorthodox servers respond 200 in error case
|
||||||
|
if failureStatus || tokError.code != "" {
|
||||||
|
return nil, refreshToken, tokError
|
||||||
|
}
|
||||||
|
if token.Value == "" {
|
||||||
|
return nil, refreshToken, errors.New("auth: server response missing access_token")
|
||||||
|
}
|
||||||
|
return token, refreshToken, nil
|
||||||
|
}
|
||||||
115
vendor/cloud.google.com/go/compute/metadata/CHANGES.md
generated
vendored
Normal file
115
vendor/cloud.google.com/go/compute/metadata/CHANGES.md
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# Changes
|
||||||
|
|
||||||
|
## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.4...compute/metadata/v0.9.0) (2025-09-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Retry on HTTP 429 ([#12932](https://github.com/googleapis/google-cloud-go/issues/12932)) ([1e91f5c](https://github.com/googleapis/google-cloud-go/commit/1e91f5c07acacd38ecdd4ff3e83e092b745e0bc2))
|
||||||
|
|
||||||
|
## [0.8.4](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.3...compute/metadata/v0.8.4) (2025-09-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Set subClient for UseDefaultClient case ([#12911](https://github.com/googleapis/google-cloud-go/issues/12911)) ([9e2646b](https://github.com/googleapis/google-cloud-go/commit/9e2646b1821231183fd775bb107c062865eeaccd))
|
||||||
|
|
||||||
|
## [0.8.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.2...compute/metadata/v0.8.3) (2025-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Disable Client timeouts for subscription client ([#12910](https://github.com/googleapis/google-cloud-go/issues/12910)) ([187a58a](https://github.com/googleapis/google-cloud-go/commit/187a58a540494e1e8562b046325b8cad8cf7af4a))
|
||||||
|
|
||||||
|
## [0.8.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.1...compute/metadata/v0.8.2) (2025-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Racy test and uninitialized subClient ([#12892](https://github.com/googleapis/google-cloud-go/issues/12892)) ([4943ca2](https://github.com/googleapis/google-cloud-go/commit/4943ca2bf83908a23806247bc4252dfb440d09cc)), refs [#12888](https://github.com/googleapis/google-cloud-go/issues/12888)
|
||||||
|
|
||||||
|
## [0.8.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.0...compute/metadata/v0.8.1) (2025-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Use separate client for subscribe methods ([#12885](https://github.com/googleapis/google-cloud-go/issues/12885)) ([76b80f8](https://github.com/googleapis/google-cloud-go/commit/76b80f8df9bf9339d175407e8c15936fe1ac1c9c))
|
||||||
|
|
||||||
|
## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.7.0...compute/metadata/v0.8.0) (2025-08-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Add Options.UseDefaultClient ([#12657](https://github.com/googleapis/google-cloud-go/issues/12657)) ([1a88209](https://github.com/googleapis/google-cloud-go/commit/1a8820900f20e038291c4bb2c5284a449196e81f)), refs [#11078](https://github.com/googleapis/google-cloud-go/issues/11078)
|
||||||
|
|
||||||
|
## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.6.0...compute/metadata/v0.7.0) (2025-05-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Allow canceling GCE detection ([#11786](https://github.com/googleapis/google-cloud-go/issues/11786)) ([78100fe](https://github.com/googleapis/google-cloud-go/commit/78100fe7e28cd30f1e10b47191ac3c9839663b64))
|
||||||
|
|
||||||
|
## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.2...compute/metadata/v0.6.0) (2024-12-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Add debug logging ([#11078](https://github.com/googleapis/google-cloud-go/issues/11078)) ([a816814](https://github.com/googleapis/google-cloud-go/commit/a81681463906e4473570a2f426eb0dc2de64e53f))
|
||||||
|
|
||||||
|
## [0.5.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.1...compute/metadata/v0.5.2) (2024-09-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Close Response Body for failed request ([#10891](https://github.com/googleapis/google-cloud-go/issues/10891)) ([e91d45e](https://github.com/googleapis/google-cloud-go/commit/e91d45e4757a9e354114509ba9800085d9e0ff1f))
|
||||||
|
|
||||||
|
## [0.5.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.0...compute/metadata/v0.5.1) (2024-09-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Check error chain for retryable error ([#10840](https://github.com/googleapis/google-cloud-go/issues/10840)) ([2bdedef](https://github.com/googleapis/google-cloud-go/commit/2bdedeff621b223d63cebc4355fcf83bc68412cd))
|
||||||
|
|
||||||
|
## [0.5.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.4.0...compute/metadata/v0.5.0) (2024-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Add sys check for windows OnGCE ([#10521](https://github.com/googleapis/google-cloud-go/issues/10521)) ([3b9a830](https://github.com/googleapis/google-cloud-go/commit/3b9a83063960d2a2ac20beb47cc15818a68bd302))
|
||||||
|
|
||||||
|
## [0.4.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.3.0...compute/metadata/v0.4.0) (2024-07-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Add context for all functions/methods ([#10370](https://github.com/googleapis/google-cloud-go/issues/10370)) ([66b8efe](https://github.com/googleapis/google-cloud-go/commit/66b8efe7ad877e052b2987bb4475477e38c67bb3))
|
||||||
|
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
* **compute/metadata:** Update OnGCE description ([#10408](https://github.com/googleapis/google-cloud-go/issues/10408)) ([6a46dca](https://github.com/googleapis/google-cloud-go/commit/6a46dca4eae4f88ec6f88822e01e5bf8aeca787f))
|
||||||
|
|
||||||
|
## [0.3.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.3...compute/metadata/v0.3.0) (2024-04-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **compute/metadata:** Add context aware functions ([#9733](https://github.com/googleapis/google-cloud-go/issues/9733)) ([e4eb5b4](https://github.com/googleapis/google-cloud-go/commit/e4eb5b46ee2aec9d2fc18300bfd66015e25a0510))
|
||||||
|
|
||||||
|
## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.2...compute/metadata/v0.2.3) (2022-12-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Switch DNS lookup to an absolute lookup ([119b410](https://github.com/googleapis/google-cloud-go/commit/119b41060c7895e45e48aee5621ad35607c4d021)), refs [#7165](https://github.com/googleapis/google-cloud-go/issues/7165)
|
||||||
|
|
||||||
|
## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.1...compute/metadata/v0.2.2) (2022-12-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compute/metadata:** Set IdleConnTimeout for http.Client ([#7084](https://github.com/googleapis/google-cloud-go/issues/7084)) ([766516a](https://github.com/googleapis/google-cloud-go/commit/766516aaf3816bfb3159efeea65aa3d1d205a3e2)), refs [#5430](https://github.com/googleapis/google-cloud-go/issues/5430)
|
||||||
|
|
||||||
|
## [0.1.0] (2022-10-26)
|
||||||
|
|
||||||
|
Initial release of metadata being it's own module.
|
||||||
202
vendor/cloud.google.com/go/compute/metadata/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/compute/metadata/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.
|
||||||
27
vendor/cloud.google.com/go/compute/metadata/README.md
generated
vendored
Normal file
27
vendor/cloud.google.com/go/compute/metadata/README.md
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Compute API
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/cloud.google.com/go/compute/metadata)
|
||||||
|
|
||||||
|
This is a utility library for communicating with Google Cloud metadata service
|
||||||
|
on Google Cloud.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get cloud.google.com/go/compute/metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
149
vendor/cloud.google.com/go/compute/metadata/log.go
generated
vendored
Normal file
149
vendor/cloud.google.com/go/compute/metadata/log.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2024 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 (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Code below this point is copied from github.com/googleapis/gax-go/v2/internallog
|
||||||
|
// to avoid the dependency. The compute/metadata module is used by too many
|
||||||
|
// non-client library modules that can't justify the dependency.
|
||||||
|
|
||||||
|
// The handler returned if logging is not enabled.
|
||||||
|
type noOpHandler struct{}
|
||||||
|
|
||||||
|
func (h noOpHandler) Enabled(_ context.Context, _ slog.Level) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h noOpHandler) Handle(_ context.Context, _ slog.Record) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h noOpHandler) WithAttrs(_ []slog.Attr) slog.Handler {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h noOpHandler) WithGroup(_ string) slog.Handler {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// httpRequest returns a lazily evaluated [slog.LogValuer] for a
|
||||||
|
// [http.Request] and the associated body.
|
||||||
|
func httpRequest(req *http.Request, body []byte) slog.LogValuer {
|
||||||
|
return &request{
|
||||||
|
req: req,
|
||||||
|
payload: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type request struct {
|
||||||
|
req *http.Request
|
||||||
|
payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *request) LogValue() slog.Value {
|
||||||
|
if r == nil || r.req == nil {
|
||||||
|
return slog.Value{}
|
||||||
|
}
|
||||||
|
var groupValueAttrs []slog.Attr
|
||||||
|
groupValueAttrs = append(groupValueAttrs, slog.String("method", r.req.Method))
|
||||||
|
groupValueAttrs = append(groupValueAttrs, slog.String("url", r.req.URL.String()))
|
||||||
|
|
||||||
|
var headerAttr []slog.Attr
|
||||||
|
for k, val := range r.req.Header {
|
||||||
|
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
||||||
|
}
|
||||||
|
if len(headerAttr) > 0 {
|
||||||
|
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.payload) > 0 {
|
||||||
|
if attr, ok := processPayload(r.payload); ok {
|
||||||
|
groupValueAttrs = append(groupValueAttrs, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slog.GroupValue(groupValueAttrs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// httpResponse returns a lazily evaluated [slog.LogValuer] for a
|
||||||
|
// [http.Response] and the associated body.
|
||||||
|
func httpResponse(resp *http.Response, body []byte) slog.LogValuer {
|
||||||
|
return &response{
|
||||||
|
resp: resp,
|
||||||
|
payload: body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type response struct {
|
||||||
|
resp *http.Response
|
||||||
|
payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *response) LogValue() slog.Value {
|
||||||
|
if r == nil {
|
||||||
|
return slog.Value{}
|
||||||
|
}
|
||||||
|
var groupValueAttrs []slog.Attr
|
||||||
|
groupValueAttrs = append(groupValueAttrs, slog.String("status", fmt.Sprint(r.resp.StatusCode)))
|
||||||
|
|
||||||
|
var headerAttr []slog.Attr
|
||||||
|
for k, val := range r.resp.Header {
|
||||||
|
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
||||||
|
}
|
||||||
|
if len(headerAttr) > 0 {
|
||||||
|
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.payload) > 0 {
|
||||||
|
if attr, ok := processPayload(r.payload); ok {
|
||||||
|
groupValueAttrs = append(groupValueAttrs, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slog.GroupValue(groupValueAttrs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processPayload(payload []byte) (slog.Attr, bool) {
|
||||||
|
peekChar := payload[0]
|
||||||
|
if peekChar == '{' {
|
||||||
|
// JSON object
|
||||||
|
var m map[string]any
|
||||||
|
if err := json.Unmarshal(payload, &m); err == nil {
|
||||||
|
return slog.Any("payload", m), true
|
||||||
|
}
|
||||||
|
} else if peekChar == '[' {
|
||||||
|
// JSON array
|
||||||
|
var m []any
|
||||||
|
if err := json.Unmarshal(payload, &m); err == nil {
|
||||||
|
return slog.Any("payload", m), true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Everything else
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
if err := json.Compact(buf, payload); err != nil {
|
||||||
|
// Write raw payload incase of error
|
||||||
|
buf.Write(payload)
|
||||||
|
}
|
||||||
|
return slog.String("payload", buf.String()), true
|
||||||
|
}
|
||||||
|
return slog.Attr{}, false
|
||||||
|
}
|
||||||
937
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
937
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,937 @@
|
|||||||
|
// 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://cloud.google.com/compute/docs/metadata/overview.
|
||||||
|
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"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(true),
|
||||||
|
subClient: newDefaultHTTPClient(false),
|
||||||
|
logger: slog.New(noOpHandler{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultHTTPClient(enableTimeouts bool) *http.Client {
|
||||||
|
transport := &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
}
|
||||||
|
c := &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
}
|
||||||
|
if enableTimeouts {
|
||||||
|
transport.IdleConnTimeout = 60 * time.Second
|
||||||
|
c.Timeout = 5 * time.Second
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(ctx context.Context, 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(ctx, c.k)
|
||||||
|
} else {
|
||||||
|
v, err = cl.GetWithContext(ctx, 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 Platforms.
|
||||||
|
// NOTE: True returned from `OnGCE` does not guarantee that the metadata server
|
||||||
|
// is accessible from this process and have all the metadata defined.
|
||||||
|
func OnGCE() bool {
|
||||||
|
return OnGCEWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnGCEWithContext reports whether this process is running on Google Compute Platforms.
|
||||||
|
// This function's return value is memoized for better performance.
|
||||||
|
// NOTE: True returned from `OnGCEWithContext` does not guarantee that the metadata server
|
||||||
|
// is accessible from this process and have all the metadata defined.
|
||||||
|
func OnGCEWithContext(ctx context.Context) bool {
|
||||||
|
onGCEOnce.Do(func() {
|
||||||
|
onGCE = defaultClient.OnGCEWithContext(ctx)
|
||||||
|
})
|
||||||
|
return onGCE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe calls Client.SubscribeWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [SubscribeWithContext].
|
||||||
|
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
return defaultClient.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeWithContext calls Client.SubscribeWithContext on the default client.
|
||||||
|
func SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, v string, ok bool) error) error {
|
||||||
|
return defaultClient.SubscribeWithContext(ctx, suffix, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get calls Client.GetWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [GetWithContext].
|
||||||
|
func Get(suffix string) (string, error) {
|
||||||
|
return defaultClient.GetWithContext(context.Background(), suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWithContext calls Client.GetWithContext on the default client.
|
||||||
|
func GetWithContext(ctx context.Context, suffix string) (string, error) {
|
||||||
|
return defaultClient.GetWithContext(ctx, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ProjectIDWithContext].
|
||||||
|
func ProjectID() (string, error) {
|
||||||
|
return defaultClient.ProjectIDWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectIDWithContext returns the current instance's project ID string.
|
||||||
|
func ProjectIDWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.ProjectIDWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [NumericProjectIDWithContext].
|
||||||
|
func NumericProjectID() (string, error) {
|
||||||
|
return defaultClient.NumericProjectIDWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumericProjectIDWithContext returns the current instance's numeric project ID.
|
||||||
|
func NumericProjectIDWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.NumericProjectIDWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InternalIPWithContext].
|
||||||
|
func InternalIP() (string, error) {
|
||||||
|
return defaultClient.InternalIPWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalIPWithContext returns the instance's primary internal IP address.
|
||||||
|
func InternalIPWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.InternalIPWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ExternalIPWithContext].
|
||||||
|
func ExternalIP() (string, error) {
|
||||||
|
return defaultClient.ExternalIPWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIPWithContext returns the instance's primary external (public) IP address.
|
||||||
|
func ExternalIPWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.ExternalIPWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email calls Client.EmailWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [EmailWithContext].
|
||||||
|
func Email(serviceAccount string) (string, error) {
|
||||||
|
return defaultClient.EmailWithContext(context.Background(), serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailWithContext calls Client.EmailWithContext on the default client.
|
||||||
|
func EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
|
||||||
|
return defaultClient.EmailWithContext(ctx, serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [HostnameWithContext].
|
||||||
|
func Hostname() (string, error) {
|
||||||
|
return defaultClient.HostnameWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostnameWithContext returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func HostnameWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.HostnameWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InstanceTagsWithContext].
|
||||||
|
func InstanceTags() ([]string, error) {
|
||||||
|
return defaultClient.InstanceTagsWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTagsWithContext returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func InstanceTagsWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
return defaultClient.InstanceTagsWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InstanceIDWithContext].
|
||||||
|
func InstanceID() (string, error) {
|
||||||
|
return defaultClient.InstanceIDWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceIDWithContext returns the current VM's numeric instance ID.
|
||||||
|
func InstanceIDWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.InstanceIDWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InstanceNameWithContext].
|
||||||
|
func InstanceName() (string, error) {
|
||||||
|
return defaultClient.InstanceNameWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceNameWithContext returns the current VM's instance ID string.
|
||||||
|
func InstanceNameWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.InstanceNameWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ZoneWithContext].
|
||||||
|
func Zone() (string, error) {
|
||||||
|
return defaultClient.ZoneWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneWithContext returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func ZoneWithContext(ctx context.Context) (string, error) {
|
||||||
|
return defaultClient.ZoneWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributes calls Client.InstanceAttributesWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InstanceAttributesWithContext.
|
||||||
|
func InstanceAttributes() ([]string, error) {
|
||||||
|
return defaultClient.InstanceAttributesWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
|
||||||
|
func InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
return defaultClient.InstanceAttributesWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributes calls Client.ProjectAttributesWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ProjectAttributesWithContext].
|
||||||
|
func ProjectAttributes() ([]string, error) {
|
||||||
|
return defaultClient.ProjectAttributesWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributesWithContext calls Client.ProjectAttributesWithContext on the default client.
|
||||||
|
func ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
return defaultClient.ProjectAttributesWithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributeValue calls Client.InstanceAttributeValueWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [InstanceAttributeValueWithContext].
|
||||||
|
func InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.InstanceAttributeValueWithContext(context.Background(), attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributeValueWithContext calls Client.InstanceAttributeValueWithContext on the default client.
|
||||||
|
func InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
||||||
|
return defaultClient.InstanceAttributeValueWithContext(ctx, attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue calls Client.ProjectAttributeValueWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ProjectAttributeValueWithContext].
|
||||||
|
func ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.ProjectAttributeValueWithContext(context.Background(), attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValueWithContext calls Client.ProjectAttributeValueWithContext on the default client.
|
||||||
|
func ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
||||||
|
return defaultClient.ProjectAttributeValueWithContext(ctx, attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes calls Client.ScopesWithContext on the default client.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [ScopesWithContext].
|
||||||
|
func Scopes(serviceAccount string) ([]string, error) {
|
||||||
|
return defaultClient.ScopesWithContext(context.Background(), serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScopesWithContext calls Client.ScopesWithContext on the default client.
|
||||||
|
func ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
|
||||||
|
return defaultClient.ScopesWithContext(ctx, 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
|
||||||
|
// subClient by default is a HTTP Client that is only used for subscribe
|
||||||
|
// methods that should not specify a timeout. If the user specifies a client
|
||||||
|
// this with be the same as 'hc'.
|
||||||
|
subClient *http.Client
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options for configuring a [Client].
|
||||||
|
type Options struct {
|
||||||
|
// Client is the HTTP client used to make requests. Optional.
|
||||||
|
// If UseDefaultClient is true, this field is ignored.
|
||||||
|
// If this field is nil, a new default http.Client will be created.
|
||||||
|
Client *http.Client
|
||||||
|
// Logger is used to log information about HTTP request and responses.
|
||||||
|
// If not provided, nothing will be logged. Optional.
|
||||||
|
Logger *slog.Logger
|
||||||
|
// UseDefaultClient specifies that the client should use the same default
|
||||||
|
// internal http.Client that is used in functions such as GetWithContext.
|
||||||
|
// This is useful for sharing a single TCP connection pool across requests.
|
||||||
|
// The difference vs GetWithContext is the ability to use this struct
|
||||||
|
// to provide a custom logger. If this field is true, the Client
|
||||||
|
// field is ignored.
|
||||||
|
UseDefaultClient bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 internal Client that is
|
||||||
|
// also used in functions such as GetWithContext. This is useful for sharing
|
||||||
|
// a single TCP connection pool across requests.
|
||||||
|
func NewClient(c *http.Client) *Client {
|
||||||
|
if c == nil {
|
||||||
|
// Preserve original behavior for nil argument.
|
||||||
|
return defaultClient
|
||||||
|
}
|
||||||
|
// Return a new client with a no-op logger for backward compatibility.
|
||||||
|
return &Client{hc: c, subClient: c, logger: slog.New(noOpHandler{})}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithOptions returns a Client that is configured with the provided Options.
|
||||||
|
func NewWithOptions(opts *Options) *Client {
|
||||||
|
// Preserve original behavior for nil opts.
|
||||||
|
if opts == nil {
|
||||||
|
return defaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle explicit request for the internal default http.Client.
|
||||||
|
if opts.UseDefaultClient {
|
||||||
|
logger := opts.Logger
|
||||||
|
if logger == nil {
|
||||||
|
logger = slog.New(noOpHandler{})
|
||||||
|
}
|
||||||
|
return &Client{hc: defaultClient.hc, subClient: defaultClient.subClient, logger: logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle isolated client creation.
|
||||||
|
client := opts.Client
|
||||||
|
subClient := opts.Client
|
||||||
|
if client == nil {
|
||||||
|
client = newDefaultHTTPClient(true)
|
||||||
|
subClient = newDefaultHTTPClient(false)
|
||||||
|
}
|
||||||
|
logger := opts.Logger
|
||||||
|
if logger == nil {
|
||||||
|
logger = slog.New(noOpHandler{})
|
||||||
|
}
|
||||||
|
return &Client{hc: client, subClient: subClient, logger: logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: metadataRequestStrategy is assigned to a variable for test stubbing purposes.
|
||||||
|
var metadataRequestStrategy = func(ctx context.Context, httpClient *http.Client, resc chan bool) {
|
||||||
|
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := httpClient.Do(req.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: dnsRequestStrategy is assigned to a variable for test stubbing purposes.
|
||||||
|
var dnsRequestStrategy = func(ctx context.Context, resc chan bool) {
|
||||||
|
resolver := &net.Resolver{}
|
||||||
|
addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resc <- strsContains(addrs, metadataIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnGCEWithContext reports whether this process is running on Google Compute Platforms.
|
||||||
|
// NOTE: True returned from `OnGCEWithContext` does not guarantee that the metadata server
|
||||||
|
// is accessible from this process and have all the metadata defined.
|
||||||
|
func (c *Client) OnGCEWithContext(ctx context.Context) bool {
|
||||||
|
// The user explicitly said they're on GCE, so trust them.
|
||||||
|
if os.Getenv(metadataHostEnv) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resc := make(chan bool, 2)
|
||||||
|
|
||||||
|
// Try two strategies in parallel.
|
||||||
|
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||||
|
go metadataRequestStrategy(ctx, c.hc, resc)
|
||||||
|
go dnsRequestStrategy(ctx, resc)
|
||||||
|
|
||||||
|
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.
|
||||||
|
// Ensure cancellations from the calling context are respected.
|
||||||
|
waitContext, cancelWait := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancelWait()
|
||||||
|
select {
|
||||||
|
case res = <-resc:
|
||||||
|
return res
|
||||||
|
case <-waitContext.Done():
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(ctx context.Context, suffix string) (value, etag string, err error) {
|
||||||
|
return c.getETagWithSubClient(ctx, suffix, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getETagWithSubClient(ctx context.Context, suffix string, enableSubClient bool) (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(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.NewRequestWithContext(ctx, "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
|
||||||
|
var body []byte
|
||||||
|
retryer := newRetryer()
|
||||||
|
hc := c.hc
|
||||||
|
if enableSubClient {
|
||||||
|
hc = c.subClient
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
c.logger.DebugContext(ctx, "metadata request", "request", httpRequest(req, nil))
|
||||||
|
res, reqErr = hc.Do(req)
|
||||||
|
var code int
|
||||||
|
if res != nil {
|
||||||
|
code = res.StatusCode
|
||||||
|
body, err = io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
res.Body.Close()
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
c.logger.DebugContext(ctx, "metadata response", "response", httpResponse(res, body))
|
||||||
|
res.Body.Close()
|
||||||
|
}
|
||||||
|
if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry {
|
||||||
|
if res != nil && res.Body != nil {
|
||||||
|
res.Body.Close()
|
||||||
|
}
|
||||||
|
if err := sleep(ctx, delay); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if reqErr != nil {
|
||||||
|
return "", "", reqErr
|
||||||
|
}
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return "", "", NotDefinedError(suffix)
|
||||||
|
}
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return "", "", &Error{Code: res.StatusCode, Message: string(body)}
|
||||||
|
}
|
||||||
|
return string(body), 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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.GetWithContext].
|
||||||
|
func (c *Client) Get(suffix string) (string, error) {
|
||||||
|
return c.GetWithContext(context.Background(), suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWithContext 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.
|
||||||
|
//
|
||||||
|
// NOTE: Without an extra deadline in the context this call can take in the
|
||||||
|
// worst case, with internal backoff retries, up to 15 seconds (e.g. when server
|
||||||
|
// is responding slowly). Pass context with additional timeouts when needed.
|
||||||
|
func (c *Client) GetWithContext(ctx context.Context, suffix string) (string, error) {
|
||||||
|
val, _, err := c.getETag(ctx, suffix)
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getTrimmed(ctx context.Context, suffix string) (s string, err error) {
|
||||||
|
s, err = c.GetWithContext(ctx, suffix)
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) lines(ctx context.Context, suffix string) ([]string, error) {
|
||||||
|
j, err := c.GetWithContext(ctx, 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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ProjectIDWithContext].
|
||||||
|
func (c *Client) ProjectID() (string, error) { return c.ProjectIDWithContext(context.Background()) }
|
||||||
|
|
||||||
|
// ProjectIDWithContext returns the current instance's project ID string.
|
||||||
|
func (c *Client) ProjectIDWithContext(ctx context.Context) (string, error) { return projID.get(ctx, c) }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.NumericProjectIDWithContext].
|
||||||
|
func (c *Client) NumericProjectID() (string, error) {
|
||||||
|
return c.NumericProjectIDWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumericProjectIDWithContext returns the current instance's numeric project ID.
|
||||||
|
func (c *Client) NumericProjectIDWithContext(ctx context.Context) (string, error) {
|
||||||
|
return projNum.get(ctx, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InstanceIDWithContext].
|
||||||
|
func (c *Client) InstanceID() (string, error) {
|
||||||
|
return c.InstanceIDWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceIDWithContext returns the current VM's numeric instance ID.
|
||||||
|
func (c *Client) InstanceIDWithContext(ctx context.Context) (string, error) {
|
||||||
|
return instID.get(ctx, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InternalIPWithContext].
|
||||||
|
func (c *Client) InternalIP() (string, error) {
|
||||||
|
return c.InternalIPWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalIPWithContext returns the instance's primary internal IP address.
|
||||||
|
func (c *Client) InternalIPWithContext(ctx context.Context) (string, error) {
|
||||||
|
return c.getTrimmed(ctx, "instance/network-interfaces/0/ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email returns the email address associated with the service account.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.EmailWithContext].
|
||||||
|
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||||
|
return c.EmailWithContext(context.Background(), serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailWithContext returns the email address associated with the service account.
|
||||||
|
// The serviceAccount parameter default value (empty string or "default" value)
|
||||||
|
// will use the instance's main account.
|
||||||
|
func (c *Client) EmailWithContext(ctx context.Context, serviceAccount string) (string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.getTrimmed(ctx, "instance/service-accounts/"+serviceAccount+"/email")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ExternalIPWithContext].
|
||||||
|
func (c *Client) ExternalIP() (string, error) {
|
||||||
|
return c.ExternalIPWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIPWithContext returns the instance's primary external (public) IP address.
|
||||||
|
func (c *Client) ExternalIPWithContext(ctx context.Context) (string, error) {
|
||||||
|
return c.getTrimmed(ctx, "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".
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.HostnameWithContext].
|
||||||
|
func (c *Client) Hostname() (string, error) {
|
||||||
|
return c.HostnameWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostnameWithContext returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func (c *Client) HostnameWithContext(ctx context.Context) (string, error) {
|
||||||
|
return c.getTrimmed(ctx, "instance/hostname")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InstanceTagsWithContext].
|
||||||
|
func (c *Client) InstanceTags() ([]string, error) {
|
||||||
|
return c.InstanceTagsWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTagsWithContext returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func (c *Client) InstanceTagsWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
var s []string
|
||||||
|
j, err := c.GetWithContext(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InstanceNameWithContext].
|
||||||
|
func (c *Client) InstanceName() (string, error) {
|
||||||
|
return c.InstanceNameWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceNameWithContext returns the current VM's instance ID string.
|
||||||
|
func (c *Client) InstanceNameWithContext(ctx context.Context) (string, error) {
|
||||||
|
return c.getTrimmed(ctx, "instance/name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ZoneWithContext].
|
||||||
|
func (c *Client) Zone() (string, error) {
|
||||||
|
return c.ZoneWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneWithContext returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func (c *Client) ZoneWithContext(ctx context.Context) (string, error) {
|
||||||
|
zone, err := c.getTrimmed(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InstanceAttributesWithContext].
|
||||||
|
func (c *Client) InstanceAttributes() ([]string, error) {
|
||||||
|
return c.InstanceAttributesWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributesWithContext 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) InstanceAttributesWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
return c.lines(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ProjectAttributesWithContext].
|
||||||
|
func (c *Client) ProjectAttributes() ([]string, error) {
|
||||||
|
return c.ProjectAttributesWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributesWithContext 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) ProjectAttributesWithContext(ctx context.Context) ([]string, error) {
|
||||||
|
return c.lines(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.InstanceAttributeValueWithContext].
|
||||||
|
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return c.InstanceAttributeValueWithContext(context.Background(), attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributeValueWithContext 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) InstanceAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
||||||
|
return c.GetWithContext(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ProjectAttributeValueWithContext].
|
||||||
|
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return c.ProjectAttributeValueWithContext(context.Background(), attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValueWithContext 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) ProjectAttributeValueWithContext(ctx context.Context, attr string) (string, error) {
|
||||||
|
return c.GetWithContext(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.ScopesWithContext].
|
||||||
|
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
||||||
|
return c.ScopesWithContext(context.Background(), serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScopesWithContext 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) ScopesWithContext(ctx context.Context, serviceAccount string) ([]string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.lines(ctx, "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.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use the context aware variant [Client.SubscribeWithContext].
|
||||||
|
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
return c.SubscribeWithContext(context.Background(), suffix, func(ctx context.Context, v string, ok bool) error { return fn(v, ok) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeWithContext 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.
|
||||||
|
//
|
||||||
|
// SubscribeWithContext 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) SubscribeWithContext(ctx context.Context, suffix string, fn func(ctx context.Context, 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.getETagWithSubClient(ctx, suffix, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fn(ctx, 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.getETagWithSubClient(ctx, suffix+url.QueryEscape(lastETag), true)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, deleted := err.(NotDefinedError); !deleted {
|
||||||
|
time.Sleep(failedSubscribeSleep)
|
||||||
|
continue // Retry on other errors.
|
||||||
|
}
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
lastETag = etag
|
||||||
|
|
||||||
|
if err := fn(ctx, 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)
|
||||||
|
}
|
||||||
117
vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
Normal file
117
vendor/cloud.google.com/go/compute/metadata/retry.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// 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(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 status == http.StatusTooManyRequests {
|
||||||
|
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
|
||||||
|
}
|
||||||
31
vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
Normal file
31
vendor/cloud.google.com/go/compute/metadata/retry_linux.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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 (
|
||||||
|
"errors"
|
||||||
|
"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 errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.ECONNREFUSED)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
vendor/cloud.google.com/go/compute/metadata/syscheck.go
generated
vendored
Normal file
28
vendor/cloud.google.com/go/compute/metadata/syscheck.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2024 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 !windows && !linux
|
||||||
|
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||||
|
var systemInfoSuggestsGCE = func() bool {
|
||||||
|
// We don't currently have checks for other GOOS
|
||||||
|
return false
|
||||||
|
}
|
||||||
30
vendor/cloud.google.com/go/compute/metadata/syscheck_linux.go
generated
vendored
Normal file
30
vendor/cloud.google.com/go/compute/metadata/syscheck_linux.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2024 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
|
||||||
|
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||||
|
var systemInfoSuggestsGCE = func() bool {
|
||||||
|
b, _ := os.ReadFile("/sys/class/dmi/id/product_name")
|
||||||
|
|
||||||
|
name := strings.TrimSpace(string(b))
|
||||||
|
return name == "Google" || name == "Google Compute Engine"
|
||||||
|
}
|
||||||
39
vendor/cloud.google.com/go/compute/metadata/syscheck_windows.go
generated
vendored
Normal file
39
vendor/cloud.google.com/go/compute/metadata/syscheck_windows.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2024 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 windows
|
||||||
|
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||||
|
var systemInfoSuggestsGCE = func() bool {
|
||||||
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\HardwareConfig\Current`, registry.QUERY_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer k.Close()
|
||||||
|
|
||||||
|
s, _, err := k.GetStringValue("SystemProductName")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return strings.HasPrefix(s, "Google")
|
||||||
|
}
|
||||||
202
vendor/cloud.google.com/go/iam/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/iam/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.
|
||||||
17
vendor/cloud.google.com/go/iam/credentials/apiv1/auxiliary.go
generated
vendored
Normal file
17
vendor/cloud.google.com/go/iam/credentials/apiv1/auxiliary.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2024 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
|
||||||
|
//
|
||||||
|
// https://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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
|
||||||
|
|
||||||
|
package credentials
|
||||||
855
vendor/cloud.google.com/go/iam/credentials/apiv1/credentialspb/common.pb.go
generated
vendored
Normal file
855
vendor/cloud.google.com/go/iam/credentials/apiv1/credentialspb/common.pb.go
generated
vendored
Normal file
@@ -0,0 +1,855 @@
|
|||||||
|
// Copyright 2024 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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc v4.25.3
|
||||||
|
// source: google/iam/credentials/v1/common.proto
|
||||||
|
|
||||||
|
package credentialspb
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
|
||||||
|
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
durationpb "google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type GenerateAccessTokenRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Required. The resource name of the service account for which the credentials
|
||||||
|
// are requested, in the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
// The sequence of service accounts in a delegation chain. Each service
|
||||||
|
// account must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on its next service account in the chain. The last service account in the
|
||||||
|
// chain must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on the service account that is specified in the `name` field of the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// The delegates must have the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Delegates []string `protobuf:"bytes,2,rep,name=delegates,proto3" json:"delegates,omitempty"`
|
||||||
|
// Required. Code to identify the scopes to be included in the OAuth 2.0 access token.
|
||||||
|
// See https://developers.google.com/identity/protocols/googlescopes for more
|
||||||
|
// information.
|
||||||
|
// At least one value required.
|
||||||
|
Scope []string `protobuf:"bytes,4,rep,name=scope,proto3" json:"scope,omitempty"`
|
||||||
|
// The desired lifetime duration of the access token in seconds.
|
||||||
|
// Must be set to a value less than or equal to 3600 (1 hour). If a value is
|
||||||
|
// not specified, the token's lifetime will be set to a default value of one
|
||||||
|
// hour.
|
||||||
|
Lifetime *durationpb.Duration `protobuf:"bytes,7,opt,name=lifetime,proto3" json:"lifetime,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) Reset() {
|
||||||
|
*x = GenerateAccessTokenRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GenerateAccessTokenRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GenerateAccessTokenRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GenerateAccessTokenRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) GetDelegates() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Delegates
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) GetScope() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Scope
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenRequest) GetLifetime() *durationpb.Duration {
|
||||||
|
if x != nil {
|
||||||
|
return x.Lifetime
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerateAccessTokenResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// The OAuth 2.0 access token.
|
||||||
|
AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||||
|
// Token expiration time.
|
||||||
|
// The expiration time is always set.
|
||||||
|
ExpireTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenResponse) Reset() {
|
||||||
|
*x = GenerateAccessTokenResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GenerateAccessTokenResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GenerateAccessTokenResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GenerateAccessTokenResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenResponse) GetAccessToken() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AccessToken
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateAccessTokenResponse) GetExpireTime() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.ExpireTime
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignBlobRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Required. The resource name of the service account for which the credentials
|
||||||
|
// are requested, in the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
// The sequence of service accounts in a delegation chain. Each service
|
||||||
|
// account must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on its next service account in the chain. The last service account in the
|
||||||
|
// chain must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on the service account that is specified in the `name` field of the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// The delegates must have the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Delegates []string `protobuf:"bytes,3,rep,name=delegates,proto3" json:"delegates,omitempty"`
|
||||||
|
// Required. The bytes to sign.
|
||||||
|
Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) Reset() {
|
||||||
|
*x = SignBlobRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SignBlobRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SignBlobRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SignBlobRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) GetDelegates() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Delegates
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobRequest) GetPayload() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Payload
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignBlobResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// The ID of the key used to sign the blob.
|
||||||
|
KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"`
|
||||||
|
// The signed blob.
|
||||||
|
SignedBlob []byte `protobuf:"bytes,4,opt,name=signed_blob,json=signedBlob,proto3" json:"signed_blob,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobResponse) Reset() {
|
||||||
|
*x = SignBlobResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SignBlobResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SignBlobResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SignBlobResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SignBlobResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobResponse) GetKeyId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.KeyId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignBlobResponse) GetSignedBlob() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.SignedBlob
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignJwtRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Required. The resource name of the service account for which the credentials
|
||||||
|
// are requested, in the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
// The sequence of service accounts in a delegation chain. Each service
|
||||||
|
// account must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on its next service account in the chain. The last service account in the
|
||||||
|
// chain must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on the service account that is specified in the `name` field of the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// The delegates must have the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Delegates []string `protobuf:"bytes,3,rep,name=delegates,proto3" json:"delegates,omitempty"`
|
||||||
|
// Required. The JWT payload to sign: a JSON object that contains a JWT Claims Set.
|
||||||
|
Payload string `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) Reset() {
|
||||||
|
*x = SignJwtRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SignJwtRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SignJwtRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SignJwtRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) GetDelegates() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Delegates
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtRequest) GetPayload() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Payload
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignJwtResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// The ID of the key used to sign the JWT.
|
||||||
|
KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"`
|
||||||
|
// The signed JWT.
|
||||||
|
SignedJwt string `protobuf:"bytes,2,opt,name=signed_jwt,json=signedJwt,proto3" json:"signed_jwt,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtResponse) Reset() {
|
||||||
|
*x = SignJwtResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SignJwtResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SignJwtResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[5]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SignJwtResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SignJwtResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtResponse) GetKeyId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.KeyId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SignJwtResponse) GetSignedJwt() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.SignedJwt
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerateIdTokenRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// Required. The resource name of the service account for which the credentials
|
||||||
|
// are requested, in the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
// The sequence of service accounts in a delegation chain. Each service
|
||||||
|
// account must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on its next service account in the chain. The last service account in the
|
||||||
|
// chain must be granted the `roles/iam.serviceAccountTokenCreator` role
|
||||||
|
// on the service account that is specified in the `name` field of the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// The delegates must have the following format:
|
||||||
|
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard
|
||||||
|
// character is required; replacing it with a project ID is invalid.
|
||||||
|
Delegates []string `protobuf:"bytes,2,rep,name=delegates,proto3" json:"delegates,omitempty"`
|
||||||
|
// Required. The audience for the token, such as the API or account that this token
|
||||||
|
// grants access to.
|
||||||
|
Audience string `protobuf:"bytes,3,opt,name=audience,proto3" json:"audience,omitempty"`
|
||||||
|
// Include the service account email in the token. If set to `true`, the
|
||||||
|
// token will contain `email` and `email_verified` claims.
|
||||||
|
IncludeEmail bool `protobuf:"varint,4,opt,name=include_email,json=includeEmail,proto3" json:"include_email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) Reset() {
|
||||||
|
*x = GenerateIdTokenRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GenerateIdTokenRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[6]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GenerateIdTokenRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GenerateIdTokenRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) GetDelegates() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Delegates
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) GetAudience() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Audience
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenRequest) GetIncludeEmail() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.IncludeEmail
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerateIdTokenResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
// The OpenId Connect ID token.
|
||||||
|
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenResponse) Reset() {
|
||||||
|
*x = GenerateIdTokenResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GenerateIdTokenResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_google_iam_credentials_v1_common_proto_msgTypes[7]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GenerateIdTokenResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GenerateIdTokenResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GenerateIdTokenResponse) GetToken() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Token
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_google_iam_credentials_v1_common_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_google_iam_credentials_v1_common_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x26, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
|
||||||
|
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||||
|
0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73,
|
||||||
|
0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||||
|
0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69,
|
||||||
|
0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
||||||
|
0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||||
|
0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
|
||||||
|
0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||||
|
0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x22, 0xcb, 0x01, 0x0a, 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63,
|
||||||
|
0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||||
|
0x3d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x29, 0xe0,
|
||||||
|
0x41, 0x02, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x69, 0x61, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
|
0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||||
|
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c,
|
||||||
|
0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
|
||||||
|
0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x05,
|
||||||
|
0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,
|
||||||
|
0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x69, 0x66, 0x65, 0x74,
|
||||||
|
0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x7d,
|
||||||
|
0x0a, 0x1b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
|
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a,
|
||||||
|
0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
|
0x12, 0x3b, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
|
||||||
|
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||||
|
0x70, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x8d, 0x01,
|
||||||
|
0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
|
0x74, 0x12, 0x3d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
|
||||||
|
0x29, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x69, 0x61, 0x6d, 0x2e, 0x67, 0x6f, 0x6f,
|
||||||
|
0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x72, 0x76,
|
||||||
|
0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
|
0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20,
|
||||||
|
0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1d,
|
||||||
|
0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42,
|
||||||
|
0x03, 0xe0, 0x41, 0x02, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x4a, 0x0a,
|
||||||
|
0x10, 0x53, 0x69, 0x67, 0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
|
0x65, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e,
|
||||||
|
0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73,
|
||||||
|
0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x22, 0x8c, 0x01, 0x0a, 0x0e, 0x53, 0x69,
|
||||||
|
0x67, 0x6e, 0x4a, 0x77, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04,
|
||||||
|
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x29, 0xe0, 0x41, 0x02, 0xfa,
|
||||||
|
0x41, 0x23, 0x0a, 0x21, 0x69, 0x61, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
|
||||||
|
0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63,
|
||||||
|
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64,
|
||||||
|
0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
|
||||||
|
0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79,
|
||||||
|
0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52,
|
||||||
|
0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x47, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e,
|
||||||
|
0x4a, 0x77, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6b,
|
||||||
|
0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79,
|
||||||
|
0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6a, 0x77, 0x74,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4a, 0x77,
|
||||||
|
0x74, 0x22, 0xbb, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64,
|
||||||
|
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04,
|
||||||
|
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x29, 0xe0, 0x41, 0x02, 0xfa,
|
||||||
|
0x41, 0x23, 0x0a, 0x21, 0x69, 0x61, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
|
||||||
|
0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63,
|
||||||
|
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64,
|
||||||
|
0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
|
||||||
|
0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x61, 0x75, 0x64,
|
||||||
|
0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,
|
||||||
|
0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e,
|
||||||
|
0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
|
0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22,
|
||||||
|
0x2f, 0x0a, 0x17, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x6b,
|
||||||
|
0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f,
|
||||||
|
0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
|
0x42, 0xac, 0x02, 0xea, 0x41, 0x59, 0x0a, 0x21, 0x69, 0x61, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x72, 0x76, 0x69,
|
||||||
|
0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34, 0x70, 0x72, 0x6f, 0x6a, 0x65,
|
||||||
|
0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x73, 0x65,
|
||||||
|
0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x73,
|
||||||
|
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x0a,
|
||||||
|
0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75,
|
||||||
|
0x64, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||||
|
0x73, 0x2e, 0x76, 0x31, 0x42, 0x19, 0x49, 0x41, 0x4d, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||||
|
0x69, 0x61, 0x6c, 0x73, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
|
||||||
|
0x01, 0x5a, 0x45, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||||
|
0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65,
|
||||||
|
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x70, 0x62, 0x3b, 0x63, 0x72, 0x65, 0x64, 0x65,
|
||||||
|
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x1f, 0x47, 0x6f,
|
||||||
|
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x43,
|
||||||
|
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1f,
|
||||||
|
0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d,
|
||||||
|
0x5c, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x5c, 0x56, 0x31, 0x62,
|
||||||
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_google_iam_credentials_v1_common_proto_rawDescOnce sync.Once
|
||||||
|
file_google_iam_credentials_v1_common_proto_rawDescData = file_google_iam_credentials_v1_common_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_google_iam_credentials_v1_common_proto_rawDescGZIP() []byte {
|
||||||
|
file_google_iam_credentials_v1_common_proto_rawDescOnce.Do(func() {
|
||||||
|
file_google_iam_credentials_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_iam_credentials_v1_common_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_google_iam_credentials_v1_common_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_google_iam_credentials_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||||
|
var file_google_iam_credentials_v1_common_proto_goTypes = []any{
|
||||||
|
(*GenerateAccessTokenRequest)(nil), // 0: google.iam.credentials.v1.GenerateAccessTokenRequest
|
||||||
|
(*GenerateAccessTokenResponse)(nil), // 1: google.iam.credentials.v1.GenerateAccessTokenResponse
|
||||||
|
(*SignBlobRequest)(nil), // 2: google.iam.credentials.v1.SignBlobRequest
|
||||||
|
(*SignBlobResponse)(nil), // 3: google.iam.credentials.v1.SignBlobResponse
|
||||||
|
(*SignJwtRequest)(nil), // 4: google.iam.credentials.v1.SignJwtRequest
|
||||||
|
(*SignJwtResponse)(nil), // 5: google.iam.credentials.v1.SignJwtResponse
|
||||||
|
(*GenerateIdTokenRequest)(nil), // 6: google.iam.credentials.v1.GenerateIdTokenRequest
|
||||||
|
(*GenerateIdTokenResponse)(nil), // 7: google.iam.credentials.v1.GenerateIdTokenResponse
|
||||||
|
(*durationpb.Duration)(nil), // 8: google.protobuf.Duration
|
||||||
|
(*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp
|
||||||
|
}
|
||||||
|
var file_google_iam_credentials_v1_common_proto_depIdxs = []int32{
|
||||||
|
8, // 0: google.iam.credentials.v1.GenerateAccessTokenRequest.lifetime:type_name -> google.protobuf.Duration
|
||||||
|
9, // 1: google.iam.credentials.v1.GenerateAccessTokenResponse.expire_time:type_name -> google.protobuf.Timestamp
|
||||||
|
2, // [2:2] is the sub-list for method output_type
|
||||||
|
2, // [2:2] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_google_iam_credentials_v1_common_proto_init() }
|
||||||
|
func file_google_iam_credentials_v1_common_proto_init() {
|
||||||
|
if File_google_iam_credentials_v1_common_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GenerateAccessTokenRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GenerateAccessTokenResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*SignBlobRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*SignBlobResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*SignJwtRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*SignJwtResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GenerateIdTokenRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GenerateIdTokenResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_google_iam_credentials_v1_common_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 8,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_google_iam_credentials_v1_common_proto_goTypes,
|
||||||
|
DependencyIndexes: file_google_iam_credentials_v1_common_proto_depIdxs,
|
||||||
|
MessageInfos: file_google_iam_credentials_v1_common_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_google_iam_credentials_v1_common_proto = out.File
|
||||||
|
file_google_iam_credentials_v1_common_proto_rawDesc = nil
|
||||||
|
file_google_iam_credentials_v1_common_proto_goTypes = nil
|
||||||
|
file_google_iam_credentials_v1_common_proto_depIdxs = nil
|
||||||
|
}
|
||||||
375
vendor/cloud.google.com/go/iam/credentials/apiv1/credentialspb/iamcredentials.pb.go
generated
vendored
Normal file
375
vendor/cloud.google.com/go/iam/credentials/apiv1/credentialspb/iamcredentials.pb.go
generated
vendored
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
// Copyright 2024 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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc v4.25.3
|
||||||
|
// source: google/iam/credentials/v1/iamcredentials.proto
|
||||||
|
|
||||||
|
package credentialspb
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
var File_google_iam_credentials_v1_iamcredentials_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_google_iam_credentials_v1_iamcredentials_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x63,
|
||||||
|
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x12, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f,
|
||||||
|
0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
|
0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x1a, 0x26, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x63,
|
||||||
|
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f,
|
||||||
|
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xad, 0x07, 0x0a, 0x0e, 0x49,
|
||||||
|
0x41, 0x4d, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0xec, 0x01,
|
||||||
|
0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
|
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69,
|
||||||
|
0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76,
|
||||||
|
0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
|
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x67,
|
||||||
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||||
|
0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
|
||||||
|
0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||||
|
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x66, 0xda, 0x41, 0x1d, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x64, 0x65,
|
||||||
|
0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2c, 0x6c, 0x69,
|
||||||
|
0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x40, 0x3a, 0x01, 0x2a, 0x22,
|
||||||
|
0x3b, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
|
||||||
|
0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
|
||||||
|
0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0xe4, 0x01, 0x0a,
|
||||||
|
0x0f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
|
0x12, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72,
|
||||||
|
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e,
|
||||||
|
0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d,
|
||||||
|
0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
|
0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52,
|
||||||
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6a, 0xda, 0x41, 0x25, 0x6e, 0x61, 0x6d, 0x65,
|
||||||
|
0x2c, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x61, 0x75, 0x64, 0x69, 0x65,
|
||||||
|
0x6e, 0x63, 0x65, 0x2c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6d, 0x61, 0x69,
|
||||||
|
0x6c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x3a, 0x01, 0x2a, 0x22, 0x37, 0x2f, 0x76, 0x31, 0x2f,
|
||||||
|
0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
|
||||||
|
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
|
||||||
|
0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x54, 0x6f,
|
||||||
|
0x6b, 0x65, 0x6e, 0x12, 0xb9, 0x01, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x42, 0x6c, 0x6f, 0x62,
|
||||||
|
0x12, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72,
|
||||||
|
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67,
|
||||||
|
0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67,
|
||||||
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
|
||||||
|
0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x42, 0x6c, 0x6f,
|
||||||
|
0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0xda, 0x41, 0x16, 0x6e, 0x61,
|
||||||
|
0x6d, 0x65, 0x2c, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x70, 0x61, 0x79,
|
||||||
|
0x6c, 0x6f, 0x61, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35, 0x3a, 0x01, 0x2a, 0x22, 0x30, 0x2f,
|
||||||
|
0x76, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
|
||||||
|
0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75,
|
||||||
|
0x6e, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x73, 0x69, 0x67, 0x6e, 0x42, 0x6c, 0x6f, 0x62, 0x12,
|
||||||
|
0xb5, 0x01, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x4a, 0x77, 0x74, 0x12, 0x29, 0x2e, 0x67, 0x6f,
|
||||||
|
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||||
|
0x69, 0x61, 0x6c, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4a, 0x77, 0x74, 0x52,
|
||||||
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||||
|
0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e,
|
||||||
|
0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4a, 0x77, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
|
0x73, 0x65, 0x22, 0x53, 0xda, 0x41, 0x16, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x64, 0x65, 0x6c, 0x65,
|
||||||
|
0x67, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x82, 0xd3, 0xe4,
|
||||||
|
0x93, 0x02, 0x34, 0x3a, 0x01, 0x2a, 0x22, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
|
||||||
|
0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x73, 0x65, 0x72,
|
||||||
|
0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x3a,
|
||||||
|
0x73, 0x69, 0x67, 0x6e, 0x4a, 0x77, 0x74, 0x1a, 0x51, 0xca, 0x41, 0x1d, 0x69, 0x61, 0x6d, 0x63,
|
||||||
|
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
|
0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x2e, 0x68, 0x74, 0x74, 0x70,
|
||||||
|
0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
|
||||||
|
0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75,
|
||||||
|
0x64, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0xca, 0x01, 0x0a, 0x23, 0x63,
|
||||||
|
0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
|
||||||
|
0x69, 0x61, 0x6d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e,
|
||||||
|
0x76, 0x31, 0x42, 0x13, 0x49, 0x41, 0x4d, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||||
|
0x6c, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x45, 0x63, 0x6c, 0x6f, 0x75, 0x64,
|
||||||
|
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x69,
|
||||||
|
0x61, 0x6d, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x61,
|
||||||
|
0x70, 0x69, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73,
|
||||||
|
0x70, 0x62, 0x3b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x70, 0x62,
|
||||||
|
0xf8, 0x01, 0x01, 0xaa, 0x02, 0x1f, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f,
|
||||||
|
0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||||
|
0x6c, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1f, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43,
|
||||||
|
0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||||
|
0x69, 0x61, 0x6c, 0x73, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_google_iam_credentials_v1_iamcredentials_proto_goTypes = []any{
|
||||||
|
(*GenerateAccessTokenRequest)(nil), // 0: google.iam.credentials.v1.GenerateAccessTokenRequest
|
||||||
|
(*GenerateIdTokenRequest)(nil), // 1: google.iam.credentials.v1.GenerateIdTokenRequest
|
||||||
|
(*SignBlobRequest)(nil), // 2: google.iam.credentials.v1.SignBlobRequest
|
||||||
|
(*SignJwtRequest)(nil), // 3: google.iam.credentials.v1.SignJwtRequest
|
||||||
|
(*GenerateAccessTokenResponse)(nil), // 4: google.iam.credentials.v1.GenerateAccessTokenResponse
|
||||||
|
(*GenerateIdTokenResponse)(nil), // 5: google.iam.credentials.v1.GenerateIdTokenResponse
|
||||||
|
(*SignBlobResponse)(nil), // 6: google.iam.credentials.v1.SignBlobResponse
|
||||||
|
(*SignJwtResponse)(nil), // 7: google.iam.credentials.v1.SignJwtResponse
|
||||||
|
}
|
||||||
|
var file_google_iam_credentials_v1_iamcredentials_proto_depIdxs = []int32{
|
||||||
|
0, // 0: google.iam.credentials.v1.IAMCredentials.GenerateAccessToken:input_type -> google.iam.credentials.v1.GenerateAccessTokenRequest
|
||||||
|
1, // 1: google.iam.credentials.v1.IAMCredentials.GenerateIdToken:input_type -> google.iam.credentials.v1.GenerateIdTokenRequest
|
||||||
|
2, // 2: google.iam.credentials.v1.IAMCredentials.SignBlob:input_type -> google.iam.credentials.v1.SignBlobRequest
|
||||||
|
3, // 3: google.iam.credentials.v1.IAMCredentials.SignJwt:input_type -> google.iam.credentials.v1.SignJwtRequest
|
||||||
|
4, // 4: google.iam.credentials.v1.IAMCredentials.GenerateAccessToken:output_type -> google.iam.credentials.v1.GenerateAccessTokenResponse
|
||||||
|
5, // 5: google.iam.credentials.v1.IAMCredentials.GenerateIdToken:output_type -> google.iam.credentials.v1.GenerateIdTokenResponse
|
||||||
|
6, // 6: google.iam.credentials.v1.IAMCredentials.SignBlob:output_type -> google.iam.credentials.v1.SignBlobResponse
|
||||||
|
7, // 7: google.iam.credentials.v1.IAMCredentials.SignJwt:output_type -> google.iam.credentials.v1.SignJwtResponse
|
||||||
|
4, // [4:8] is the sub-list for method output_type
|
||||||
|
0, // [0:4] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_google_iam_credentials_v1_iamcredentials_proto_init() }
|
||||||
|
func file_google_iam_credentials_v1_iamcredentials_proto_init() {
|
||||||
|
if File_google_iam_credentials_v1_iamcredentials_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_google_iam_credentials_v1_common_proto_init()
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_google_iam_credentials_v1_iamcredentials_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 0,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_google_iam_credentials_v1_iamcredentials_proto_goTypes,
|
||||||
|
DependencyIndexes: file_google_iam_credentials_v1_iamcredentials_proto_depIdxs,
|
||||||
|
}.Build()
|
||||||
|
File_google_iam_credentials_v1_iamcredentials_proto = out.File
|
||||||
|
file_google_iam_credentials_v1_iamcredentials_proto_rawDesc = nil
|
||||||
|
file_google_iam_credentials_v1_iamcredentials_proto_goTypes = nil
|
||||||
|
file_google_iam_credentials_v1_iamcredentials_proto_depIdxs = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConnInterface
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion6
|
||||||
|
|
||||||
|
// IAMCredentialsClient is the client API for IAMCredentials service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||||
|
type IAMCredentialsClient interface {
|
||||||
|
// Generates an OAuth 2.0 access token for a service account.
|
||||||
|
GenerateAccessToken(ctx context.Context, in *GenerateAccessTokenRequest, opts ...grpc.CallOption) (*GenerateAccessTokenResponse, error)
|
||||||
|
// Generates an OpenID Connect ID token for a service account.
|
||||||
|
GenerateIdToken(ctx context.Context, in *GenerateIdTokenRequest, opts ...grpc.CallOption) (*GenerateIdTokenResponse, error)
|
||||||
|
// Signs a blob using a service account's system-managed private key.
|
||||||
|
SignBlob(ctx context.Context, in *SignBlobRequest, opts ...grpc.CallOption) (*SignBlobResponse, error)
|
||||||
|
// Signs a JWT using a service account's system-managed private key.
|
||||||
|
SignJwt(ctx context.Context, in *SignJwtRequest, opts ...grpc.CallOption) (*SignJwtResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type iAMCredentialsClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAMCredentialsClient(cc grpc.ClientConnInterface) IAMCredentialsClient {
|
||||||
|
return &iAMCredentialsClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iAMCredentialsClient) GenerateAccessToken(ctx context.Context, in *GenerateAccessTokenRequest, opts ...grpc.CallOption) (*GenerateAccessTokenResponse, error) {
|
||||||
|
out := new(GenerateAccessTokenResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/google.iam.credentials.v1.IAMCredentials/GenerateAccessToken", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iAMCredentialsClient) GenerateIdToken(ctx context.Context, in *GenerateIdTokenRequest, opts ...grpc.CallOption) (*GenerateIdTokenResponse, error) {
|
||||||
|
out := new(GenerateIdTokenResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/google.iam.credentials.v1.IAMCredentials/GenerateIdToken", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iAMCredentialsClient) SignBlob(ctx context.Context, in *SignBlobRequest, opts ...grpc.CallOption) (*SignBlobResponse, error) {
|
||||||
|
out := new(SignBlobResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/google.iam.credentials.v1.IAMCredentials/SignBlob", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iAMCredentialsClient) SignJwt(ctx context.Context, in *SignJwtRequest, opts ...grpc.CallOption) (*SignJwtResponse, error) {
|
||||||
|
out := new(SignJwtResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/google.iam.credentials.v1.IAMCredentials/SignJwt", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IAMCredentialsServer is the server API for IAMCredentials service.
|
||||||
|
type IAMCredentialsServer interface {
|
||||||
|
// Generates an OAuth 2.0 access token for a service account.
|
||||||
|
GenerateAccessToken(context.Context, *GenerateAccessTokenRequest) (*GenerateAccessTokenResponse, error)
|
||||||
|
// Generates an OpenID Connect ID token for a service account.
|
||||||
|
GenerateIdToken(context.Context, *GenerateIdTokenRequest) (*GenerateIdTokenResponse, error)
|
||||||
|
// Signs a blob using a service account's system-managed private key.
|
||||||
|
SignBlob(context.Context, *SignBlobRequest) (*SignBlobResponse, error)
|
||||||
|
// Signs a JWT using a service account's system-managed private key.
|
||||||
|
SignJwt(context.Context, *SignJwtRequest) (*SignJwtResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedIAMCredentialsServer can be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedIAMCredentialsServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*UnimplementedIAMCredentialsServer) GenerateAccessToken(context.Context, *GenerateAccessTokenRequest) (*GenerateAccessTokenResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GenerateAccessToken not implemented")
|
||||||
|
}
|
||||||
|
func (*UnimplementedIAMCredentialsServer) GenerateIdToken(context.Context, *GenerateIdTokenRequest) (*GenerateIdTokenResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GenerateIdToken not implemented")
|
||||||
|
}
|
||||||
|
func (*UnimplementedIAMCredentialsServer) SignBlob(context.Context, *SignBlobRequest) (*SignBlobResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method SignBlob not implemented")
|
||||||
|
}
|
||||||
|
func (*UnimplementedIAMCredentialsServer) SignJwt(context.Context, *SignJwtRequest) (*SignJwtResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method SignJwt not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterIAMCredentialsServer(s *grpc.Server, srv IAMCredentialsServer) {
|
||||||
|
s.RegisterService(&_IAMCredentials_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _IAMCredentials_GenerateAccessToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GenerateAccessTokenRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(IAMCredentialsServer).GenerateAccessToken(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/google.iam.credentials.v1.IAMCredentials/GenerateAccessToken",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(IAMCredentialsServer).GenerateAccessToken(ctx, req.(*GenerateAccessTokenRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _IAMCredentials_GenerateIdToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GenerateIdTokenRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(IAMCredentialsServer).GenerateIdToken(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/google.iam.credentials.v1.IAMCredentials/GenerateIdToken",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(IAMCredentialsServer).GenerateIdToken(ctx, req.(*GenerateIdTokenRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _IAMCredentials_SignBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SignBlobRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(IAMCredentialsServer).SignBlob(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/google.iam.credentials.v1.IAMCredentials/SignBlob",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(IAMCredentialsServer).SignBlob(ctx, req.(*SignBlobRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _IAMCredentials_SignJwt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SignJwtRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(IAMCredentialsServer).SignJwt(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/google.iam.credentials.v1.IAMCredentials/SignJwt",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(IAMCredentialsServer).SignJwt(ctx, req.(*SignJwtRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _IAMCredentials_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "google.iam.credentials.v1.IAMCredentials",
|
||||||
|
HandlerType: (*IAMCredentialsServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "GenerateAccessToken",
|
||||||
|
Handler: _IAMCredentials_GenerateAccessToken_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GenerateIdToken",
|
||||||
|
Handler: _IAMCredentials_GenerateIdToken_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "SignBlob",
|
||||||
|
Handler: _IAMCredentials_SignBlob_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "SignJwt",
|
||||||
|
Handler: _IAMCredentials_SignJwt_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "google/iam/credentials/v1/iamcredentials.proto",
|
||||||
|
}
|
||||||
122
vendor/cloud.google.com/go/iam/credentials/apiv1/doc.go
generated
vendored
Normal file
122
vendor/cloud.google.com/go/iam/credentials/apiv1/doc.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// Copyright 2024 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
|
||||||
|
//
|
||||||
|
// https://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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package credentials is an auto-generated package for the
|
||||||
|
// IAM Service Account Credentials API.
|
||||||
|
//
|
||||||
|
// Creates short-lived, limited-privilege credentials for IAM service
|
||||||
|
// accounts.
|
||||||
|
//
|
||||||
|
// # General documentation
|
||||||
|
//
|
||||||
|
// For information that is relevant for all client libraries please reference
|
||||||
|
// https://pkg.go.dev/cloud.google.com/go#pkg-overview. Some information on this
|
||||||
|
// page includes:
|
||||||
|
//
|
||||||
|
// - [Authentication and Authorization]
|
||||||
|
// - [Timeouts and Cancellation]
|
||||||
|
// - [Testing against Client Libraries]
|
||||||
|
// - [Debugging Client Libraries]
|
||||||
|
// - [Inspecting errors]
|
||||||
|
//
|
||||||
|
// # Example usage
|
||||||
|
//
|
||||||
|
// To get started with this package, create a client.
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
// // This snippet has been automatically generated and should be regarded as a code template only.
|
||||||
|
// // It will require modifications to work:
|
||||||
|
// // - It may require correct/in-range values for request initialization.
|
||||||
|
// // - It may require specifying regional endpoints when creating the service client as shown in:
|
||||||
|
// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
|
||||||
|
// c, err := credentials.NewIamCredentialsClient(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// // TODO: Handle error.
|
||||||
|
// }
|
||||||
|
// defer c.Close()
|
||||||
|
//
|
||||||
|
// The client will use your default application credentials. Clients should be reused instead of created as needed.
|
||||||
|
// The methods of Client are safe for concurrent use by multiple goroutines.
|
||||||
|
// The returned client must be Closed when it is done being used.
|
||||||
|
//
|
||||||
|
// # Using the Client
|
||||||
|
//
|
||||||
|
// The following is an example of making an API call with the newly created client.
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
// // This snippet has been automatically generated and should be regarded as a code template only.
|
||||||
|
// // It will require modifications to work:
|
||||||
|
// // - It may require correct/in-range values for request initialization.
|
||||||
|
// // - It may require specifying regional endpoints when creating the service client as shown in:
|
||||||
|
// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
|
||||||
|
// c, err := credentials.NewIamCredentialsClient(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// // TODO: Handle error.
|
||||||
|
// }
|
||||||
|
// defer c.Close()
|
||||||
|
//
|
||||||
|
// req := &credentialspb.GenerateAccessTokenRequest{
|
||||||
|
// // TODO: Fill request struct fields.
|
||||||
|
// // See https://pkg.go.dev/cloud.google.com/go/iam/credentials/apiv1/credentialspb#GenerateAccessTokenRequest.
|
||||||
|
// }
|
||||||
|
// resp, err := c.GenerateAccessToken(ctx, req)
|
||||||
|
// if err != nil {
|
||||||
|
// // TODO: Handle error.
|
||||||
|
// }
|
||||||
|
// // TODO: Use resp.
|
||||||
|
// _ = resp
|
||||||
|
//
|
||||||
|
// # Use of Context
|
||||||
|
//
|
||||||
|
// The ctx passed to NewIamCredentialsClient is used for authentication requests and
|
||||||
|
// for creating the underlying connection, but is not used for subsequent calls.
|
||||||
|
// Individual methods on the client use the ctx given to them.
|
||||||
|
//
|
||||||
|
// To close the open connection, use the Close() method.
|
||||||
|
//
|
||||||
|
// [Authentication and Authorization]: https://pkg.go.dev/cloud.google.com/go#hdr-Authentication_and_Authorization
|
||||||
|
// [Timeouts and Cancellation]: https://pkg.go.dev/cloud.google.com/go#hdr-Timeouts_and_Cancellation
|
||||||
|
// [Testing against Client Libraries]: https://pkg.go.dev/cloud.google.com/go#hdr-Testing
|
||||||
|
// [Debugging Client Libraries]: https://pkg.go.dev/cloud.google.com/go#hdr-Debugging
|
||||||
|
// [Inspecting errors]: https://pkg.go.dev/cloud.google.com/go#hdr-Inspecting_errors
|
||||||
|
package credentials // import "cloud.google.com/go/iam/credentials/apiv1"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// For more information on implementing a client constructor hook, see
|
||||||
|
// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors.
|
||||||
|
type clientHookParams struct{}
|
||||||
|
type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error)
|
||||||
|
|
||||||
|
var versionClient string
|
||||||
|
|
||||||
|
func getVersionClient() string {
|
||||||
|
if versionClient == "" {
|
||||||
|
return "UNKNOWN"
|
||||||
|
}
|
||||||
|
return versionClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
|
||||||
|
func DefaultAuthScopes() []string {
|
||||||
|
return []string{
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
}
|
||||||
|
}
|
||||||
747
vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client.go
generated
vendored
Normal file
747
vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client.go
generated
vendored
Normal file
@@ -0,0 +1,747 @@
|
|||||||
|
// Copyright 2024 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
|
||||||
|
//
|
||||||
|
// https://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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
credentialspb "cloud.google.com/go/iam/credentials/apiv1/credentialspb"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
"google.golang.org/api/option/internaloption"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
httptransport "google.golang.org/api/transport/http"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newIamCredentialsClientHook clientHook
|
||||||
|
|
||||||
|
// IamCredentialsCallOptions contains the retry settings for each method of IamCredentialsClient.
|
||||||
|
type IamCredentialsCallOptions struct {
|
||||||
|
GenerateAccessToken []gax.CallOption
|
||||||
|
GenerateIdToken []gax.CallOption
|
||||||
|
SignBlob []gax.CallOption
|
||||||
|
SignJwt []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultIamCredentialsGRPCClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
internaloption.WithDefaultEndpoint("iamcredentials.googleapis.com:443"),
|
||||||
|
internaloption.WithDefaultEndpointTemplate("iamcredentials.UNIVERSE_DOMAIN:443"),
|
||||||
|
internaloption.WithDefaultMTLSEndpoint("iamcredentials.mtls.googleapis.com:443"),
|
||||||
|
internaloption.WithDefaultUniverseDomain("googleapis.com"),
|
||||||
|
internaloption.WithDefaultAudience("https://iamcredentials.googleapis.com/"),
|
||||||
|
internaloption.WithDefaultScopes(DefaultAuthScopes()...),
|
||||||
|
internaloption.EnableJwtWithScope(),
|
||||||
|
internaloption.EnableNewAuthLibrary(),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultIamCredentialsCallOptions() *IamCredentialsCallOptions {
|
||||||
|
return &IamCredentialsCallOptions{
|
||||||
|
GenerateAccessToken: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.Unavailable,
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GenerateIdToken: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.Unavailable,
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SignBlob: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.Unavailable,
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SignJwt: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.Unavailable,
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultIamCredentialsRESTCallOptions() *IamCredentialsCallOptions {
|
||||||
|
return &IamCredentialsCallOptions{
|
||||||
|
GenerateAccessToken: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnHTTPCodes(gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
},
|
||||||
|
http.StatusServiceUnavailable,
|
||||||
|
http.StatusGatewayTimeout)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GenerateIdToken: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnHTTPCodes(gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
},
|
||||||
|
http.StatusServiceUnavailable,
|
||||||
|
http.StatusGatewayTimeout)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SignBlob: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnHTTPCodes(gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
},
|
||||||
|
http.StatusServiceUnavailable,
|
||||||
|
http.StatusGatewayTimeout)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SignJwt: []gax.CallOption{
|
||||||
|
gax.WithTimeout(60000 * time.Millisecond),
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnHTTPCodes(gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
},
|
||||||
|
http.StatusServiceUnavailable,
|
||||||
|
http.StatusGatewayTimeout)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// internalIamCredentialsClient is an interface that defines the methods available from IAM Service Account Credentials API.
|
||||||
|
type internalIamCredentialsClient interface {
|
||||||
|
Close() error
|
||||||
|
setGoogleClientInfo(...string)
|
||||||
|
Connection() *grpc.ClientConn
|
||||||
|
GenerateAccessToken(context.Context, *credentialspb.GenerateAccessTokenRequest, ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error)
|
||||||
|
GenerateIdToken(context.Context, *credentialspb.GenerateIdTokenRequest, ...gax.CallOption) (*credentialspb.GenerateIdTokenResponse, error)
|
||||||
|
SignBlob(context.Context, *credentialspb.SignBlobRequest, ...gax.CallOption) (*credentialspb.SignBlobResponse, error)
|
||||||
|
SignJwt(context.Context, *credentialspb.SignJwtRequest, ...gax.CallOption) (*credentialspb.SignJwtResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IamCredentialsClient is a client for interacting with IAM Service Account Credentials API.
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
//
|
||||||
|
// A service account is a special type of Google account that belongs to your
|
||||||
|
// application or a virtual machine (VM), instead of to an individual end user.
|
||||||
|
// Your application assumes the identity of the service account to call Google
|
||||||
|
// APIs, so that the users aren’t directly involved.
|
||||||
|
//
|
||||||
|
// Service account credentials are used to temporarily assume the identity
|
||||||
|
// of the service account. Supported credential types include OAuth 2.0 access
|
||||||
|
// tokens, OpenID Connect ID tokens, self-signed JSON Web Tokens (JWTs), and
|
||||||
|
// more.
|
||||||
|
type IamCredentialsClient struct {
|
||||||
|
// The internal transport-dependent client.
|
||||||
|
internalClient internalIamCredentialsClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *IamCredentialsCallOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper methods routed to the internal client.
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *IamCredentialsClient) Close() error {
|
||||||
|
return c.internalClient.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setGoogleClientInfo sets the name and version of the application in
|
||||||
|
// the `x-goog-api-client` header passed on each request. Intended for
|
||||||
|
// use by Google-written clients.
|
||||||
|
func (c *IamCredentialsClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
c.internalClient.setGoogleClientInfo(keyval...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated: Connections are now pooled so this method does not always
|
||||||
|
// return the same resource.
|
||||||
|
func (c *IamCredentialsClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.internalClient.Connection()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateAccessToken generates an OAuth 2.0 access token for a service account.
|
||||||
|
func (c *IamCredentialsClient) GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error) {
|
||||||
|
return c.internalClient.GenerateAccessToken(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIdToken generates an OpenID Connect ID token for a service account.
|
||||||
|
func (c *IamCredentialsClient) GenerateIdToken(ctx context.Context, req *credentialspb.GenerateIdTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateIdTokenResponse, error) {
|
||||||
|
return c.internalClient.GenerateIdToken(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignBlob signs a blob using a service account’s system-managed private key.
|
||||||
|
func (c *IamCredentialsClient) SignBlob(ctx context.Context, req *credentialspb.SignBlobRequest, opts ...gax.CallOption) (*credentialspb.SignBlobResponse, error) {
|
||||||
|
return c.internalClient.SignBlob(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignJwt signs a JWT using a service account’s system-managed private key.
|
||||||
|
func (c *IamCredentialsClient) SignJwt(ctx context.Context, req *credentialspb.SignJwtRequest, opts ...gax.CallOption) (*credentialspb.SignJwtResponse, error) {
|
||||||
|
return c.internalClient.SignJwt(ctx, req, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iamCredentialsGRPCClient is a client for interacting with IAM Service Account Credentials API over gRPC transport.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type iamCredentialsGRPCClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// Points back to the CallOptions field of the containing IamCredentialsClient
|
||||||
|
CallOptions **IamCredentialsCallOptions
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
iamCredentialsClient credentialspb.IAMCredentialsClient
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogHeaders []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIamCredentialsClient creates a new iam credentials client based on gRPC.
|
||||||
|
// The returned client must be Closed when it is done being used to clean up its underlying connections.
|
||||||
|
//
|
||||||
|
// A service account is a special type of Google account that belongs to your
|
||||||
|
// application or a virtual machine (VM), instead of to an individual end user.
|
||||||
|
// Your application assumes the identity of the service account to call Google
|
||||||
|
// APIs, so that the users aren’t directly involved.
|
||||||
|
//
|
||||||
|
// Service account credentials are used to temporarily assume the identity
|
||||||
|
// of the service account. Supported credential types include OAuth 2.0 access
|
||||||
|
// tokens, OpenID Connect ID tokens, self-signed JSON Web Tokens (JWTs), and
|
||||||
|
// more.
|
||||||
|
func NewIamCredentialsClient(ctx context.Context, opts ...option.ClientOption) (*IamCredentialsClient, error) {
|
||||||
|
clientOpts := defaultIamCredentialsGRPCClientOptions()
|
||||||
|
if newIamCredentialsClientHook != nil {
|
||||||
|
hookOpts, err := newIamCredentialsClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client := IamCredentialsClient{CallOptions: defaultIamCredentialsCallOptions()}
|
||||||
|
|
||||||
|
c := &iamCredentialsGRPCClient{
|
||||||
|
connPool: connPool,
|
||||||
|
iamCredentialsClient: credentialspb.NewIAMCredentialsClient(connPool),
|
||||||
|
CallOptions: &client.CallOptions,
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
client.internalClient = c
|
||||||
|
|
||||||
|
return &client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated: Connections are now pooled so this method does not always
|
||||||
|
// return the same resource.
|
||||||
|
func (c *iamCredentialsGRPCClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setGoogleClientInfo sets the name and version of the application in
|
||||||
|
// the `x-goog-api-client` header passed on each request. Intended for
|
||||||
|
// use by Google-written clients.
|
||||||
|
func (c *iamCredentialsGRPCClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
|
||||||
|
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogHeaders = []string{
|
||||||
|
"x-goog-api-client", gax.XGoogHeader(kv...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *iamCredentialsGRPCClient) Close() error {
|
||||||
|
return c.connPool.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type iamCredentialsRESTClient struct {
|
||||||
|
// The http endpoint to connect to.
|
||||||
|
endpoint string
|
||||||
|
|
||||||
|
// The http client.
|
||||||
|
httpClient *http.Client
|
||||||
|
|
||||||
|
// The x-goog-* headers to be sent with each request.
|
||||||
|
xGoogHeaders []string
|
||||||
|
|
||||||
|
// Points back to the CallOptions field of the containing IamCredentialsClient
|
||||||
|
CallOptions **IamCredentialsCallOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIamCredentialsRESTClient creates a new iam credentials rest client.
|
||||||
|
//
|
||||||
|
// A service account is a special type of Google account that belongs to your
|
||||||
|
// application or a virtual machine (VM), instead of to an individual end user.
|
||||||
|
// Your application assumes the identity of the service account to call Google
|
||||||
|
// APIs, so that the users aren’t directly involved.
|
||||||
|
//
|
||||||
|
// Service account credentials are used to temporarily assume the identity
|
||||||
|
// of the service account. Supported credential types include OAuth 2.0 access
|
||||||
|
// tokens, OpenID Connect ID tokens, self-signed JSON Web Tokens (JWTs), and
|
||||||
|
// more.
|
||||||
|
func NewIamCredentialsRESTClient(ctx context.Context, opts ...option.ClientOption) (*IamCredentialsClient, error) {
|
||||||
|
clientOpts := append(defaultIamCredentialsRESTClientOptions(), opts...)
|
||||||
|
httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
callOpts := defaultIamCredentialsRESTCallOptions()
|
||||||
|
c := &iamCredentialsRESTClient{
|
||||||
|
endpoint: endpoint,
|
||||||
|
httpClient: httpClient,
|
||||||
|
CallOptions: &callOpts,
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return &IamCredentialsClient{internalClient: c, CallOptions: callOpts}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultIamCredentialsRESTClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
internaloption.WithDefaultEndpoint("https://iamcredentials.googleapis.com"),
|
||||||
|
internaloption.WithDefaultEndpointTemplate("https://iamcredentials.UNIVERSE_DOMAIN"),
|
||||||
|
internaloption.WithDefaultMTLSEndpoint("https://iamcredentials.mtls.googleapis.com"),
|
||||||
|
internaloption.WithDefaultUniverseDomain("googleapis.com"),
|
||||||
|
internaloption.WithDefaultAudience("https://iamcredentials.googleapis.com/"),
|
||||||
|
internaloption.WithDefaultScopes(DefaultAuthScopes()...),
|
||||||
|
internaloption.EnableNewAuthLibrary(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setGoogleClientInfo sets the name and version of the application in
|
||||||
|
// the `x-goog-api-client` header passed on each request. Intended for
|
||||||
|
// use by Google-written clients.
|
||||||
|
func (c *iamCredentialsRESTClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
|
||||||
|
kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN")
|
||||||
|
c.xGoogHeaders = []string{
|
||||||
|
"x-goog-api-client", gax.XGoogHeader(kv...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *iamCredentialsRESTClient) Close() error {
|
||||||
|
// Replace httpClient with nil to force cleanup.
|
||||||
|
c.httpClient = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated: This method always returns nil.
|
||||||
|
func (c *iamCredentialsRESTClient) Connection() *grpc.ClientConn {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *iamCredentialsGRPCClient) GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error) {
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).GenerateAccessToken[0:len((*c.CallOptions).GenerateAccessToken):len((*c.CallOptions).GenerateAccessToken)], opts...)
|
||||||
|
var resp *credentialspb.GenerateAccessTokenResponse
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.iamCredentialsClient.GenerateAccessToken(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamCredentialsGRPCClient) GenerateIdToken(ctx context.Context, req *credentialspb.GenerateIdTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateIdTokenResponse, error) {
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).GenerateIdToken[0:len((*c.CallOptions).GenerateIdToken):len((*c.CallOptions).GenerateIdToken)], opts...)
|
||||||
|
var resp *credentialspb.GenerateIdTokenResponse
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.iamCredentialsClient.GenerateIdToken(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamCredentialsGRPCClient) SignBlob(ctx context.Context, req *credentialspb.SignBlobRequest, opts ...gax.CallOption) (*credentialspb.SignBlobResponse, error) {
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).SignBlob[0:len((*c.CallOptions).SignBlob):len((*c.CallOptions).SignBlob)], opts...)
|
||||||
|
var resp *credentialspb.SignBlobResponse
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.iamCredentialsClient.SignBlob(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamCredentialsGRPCClient) SignJwt(ctx context.Context, req *credentialspb.SignJwtRequest, opts ...gax.CallOption) (*credentialspb.SignJwtResponse, error) {
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).SignJwt[0:len((*c.CallOptions).SignJwt):len((*c.CallOptions).SignJwt)], opts...)
|
||||||
|
var resp *credentialspb.SignJwtResponse
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.iamCredentialsClient.SignJwt(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateAccessToken generates an OAuth 2.0 access token for a service account.
|
||||||
|
func (c *iamCredentialsRESTClient) GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error) {
|
||||||
|
m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
|
||||||
|
jsonReq, err := m.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl, err := url.Parse(c.endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseUrl.Path += fmt.Sprintf("/v1/%v:generateAccessToken", req.GetName())
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("$alt", "json;enum-encoding=int")
|
||||||
|
|
||||||
|
baseUrl.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
// Build HTTP headers from client and context metadata.
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
hds = append(hds, "Content-Type", "application/json")
|
||||||
|
headers := gax.BuildHeaders(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).GenerateAccessToken[0:len((*c.CallOptions).GenerateAccessToken):len((*c.CallOptions).GenerateAccessToken)], opts...)
|
||||||
|
unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
|
||||||
|
resp := &credentialspb.GenerateAccessTokenResponse{}
|
||||||
|
e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
if settings.Path != "" {
|
||||||
|
baseUrl.Path = settings.Path
|
||||||
|
}
|
||||||
|
httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
httpReq = httpReq.WithContext(ctx)
|
||||||
|
httpReq.Header = headers
|
||||||
|
|
||||||
|
httpRsp, err := c.httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer httpRsp.Body.Close()
|
||||||
|
|
||||||
|
if err = googleapi.CheckResponse(httpRsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := io.ReadAll(httpRsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unm.Unmarshal(buf, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, opts...)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIdToken generates an OpenID Connect ID token for a service account.
|
||||||
|
func (c *iamCredentialsRESTClient) GenerateIdToken(ctx context.Context, req *credentialspb.GenerateIdTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateIdTokenResponse, error) {
|
||||||
|
m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
|
||||||
|
jsonReq, err := m.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl, err := url.Parse(c.endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseUrl.Path += fmt.Sprintf("/v1/%v:generateIdToken", req.GetName())
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("$alt", "json;enum-encoding=int")
|
||||||
|
|
||||||
|
baseUrl.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
// Build HTTP headers from client and context metadata.
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
hds = append(hds, "Content-Type", "application/json")
|
||||||
|
headers := gax.BuildHeaders(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).GenerateIdToken[0:len((*c.CallOptions).GenerateIdToken):len((*c.CallOptions).GenerateIdToken)], opts...)
|
||||||
|
unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
|
||||||
|
resp := &credentialspb.GenerateIdTokenResponse{}
|
||||||
|
e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
if settings.Path != "" {
|
||||||
|
baseUrl.Path = settings.Path
|
||||||
|
}
|
||||||
|
httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
httpReq = httpReq.WithContext(ctx)
|
||||||
|
httpReq.Header = headers
|
||||||
|
|
||||||
|
httpRsp, err := c.httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer httpRsp.Body.Close()
|
||||||
|
|
||||||
|
if err = googleapi.CheckResponse(httpRsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := io.ReadAll(httpRsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unm.Unmarshal(buf, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, opts...)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignBlob signs a blob using a service account’s system-managed private key.
|
||||||
|
func (c *iamCredentialsRESTClient) SignBlob(ctx context.Context, req *credentialspb.SignBlobRequest, opts ...gax.CallOption) (*credentialspb.SignBlobResponse, error) {
|
||||||
|
m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
|
||||||
|
jsonReq, err := m.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl, err := url.Parse(c.endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseUrl.Path += fmt.Sprintf("/v1/%v:signBlob", req.GetName())
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("$alt", "json;enum-encoding=int")
|
||||||
|
|
||||||
|
baseUrl.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
// Build HTTP headers from client and context metadata.
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
hds = append(hds, "Content-Type", "application/json")
|
||||||
|
headers := gax.BuildHeaders(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).SignBlob[0:len((*c.CallOptions).SignBlob):len((*c.CallOptions).SignBlob)], opts...)
|
||||||
|
unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
|
||||||
|
resp := &credentialspb.SignBlobResponse{}
|
||||||
|
e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
if settings.Path != "" {
|
||||||
|
baseUrl.Path = settings.Path
|
||||||
|
}
|
||||||
|
httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
httpReq = httpReq.WithContext(ctx)
|
||||||
|
httpReq.Header = headers
|
||||||
|
|
||||||
|
httpRsp, err := c.httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer httpRsp.Body.Close()
|
||||||
|
|
||||||
|
if err = googleapi.CheckResponse(httpRsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := io.ReadAll(httpRsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unm.Unmarshal(buf, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, opts...)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignJwt signs a JWT using a service account’s system-managed private key.
|
||||||
|
func (c *iamCredentialsRESTClient) SignJwt(ctx context.Context, req *credentialspb.SignJwtRequest, opts ...gax.CallOption) (*credentialspb.SignJwtResponse, error) {
|
||||||
|
m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
|
||||||
|
jsonReq, err := m.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl, err := url.Parse(c.endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseUrl.Path += fmt.Sprintf("/v1/%v:signJwt", req.GetName())
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("$alt", "json;enum-encoding=int")
|
||||||
|
|
||||||
|
baseUrl.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
// Build HTTP headers from client and context metadata.
|
||||||
|
hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
|
||||||
|
|
||||||
|
hds = append(c.xGoogHeaders, hds...)
|
||||||
|
hds = append(hds, "Content-Type", "application/json")
|
||||||
|
headers := gax.BuildHeaders(ctx, hds...)
|
||||||
|
opts = append((*c.CallOptions).SignJwt[0:len((*c.CallOptions).SignJwt):len((*c.CallOptions).SignJwt)], opts...)
|
||||||
|
unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
|
||||||
|
resp := &credentialspb.SignJwtResponse{}
|
||||||
|
e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
if settings.Path != "" {
|
||||||
|
baseUrl.Path = settings.Path
|
||||||
|
}
|
||||||
|
httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
httpReq = httpReq.WithContext(ctx)
|
||||||
|
httpReq.Header = headers
|
||||||
|
|
||||||
|
httpRsp, err := c.httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer httpRsp.Body.Close()
|
||||||
|
|
||||||
|
if err = googleapi.CheckResponse(httpRsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := io.ReadAll(httpRsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unm.Unmarshal(buf, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, opts...)
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
23
vendor/cloud.google.com/go/iam/credentials/apiv1/version.go
generated
vendored
Normal file
23
vendor/cloud.google.com/go/iam/credentials/apiv1/version.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2023 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.
|
||||||
|
|
||||||
|
// Code generated by gapicgen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import "cloud.google.com/go/iam/internal"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
versionClient = internal.Version
|
||||||
|
}
|
||||||
18
vendor/cloud.google.com/go/iam/internal/version.go
generated
vendored
Normal file
18
vendor/cloud.google.com/go/iam/internal/version.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2022 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 internal
|
||||||
|
|
||||||
|
// Version is the current tagged release of the library.
|
||||||
|
const Version = "1.1.10"
|
||||||
77
vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md
generated
vendored
Normal file
77
vendor/github.com/adrg/xdg/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age,
|
||||||
|
body size, disability, ethnicity, sex characteristics, gender identity and
|
||||||
|
expression, level of experience, education, socio-economic status, nationality,
|
||||||
|
personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behaviour that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behaviour by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behaviour and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behaviour.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviour that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behaviour may be
|
||||||
|
reported by contacting the project team at adrg@epistack.com. All complaints
|
||||||
|
will be reviewed and investigated and will result in a response that is deemed
|
||||||
|
necessary and appropriate to the circumstances. The project team is obligated to
|
||||||
|
maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 1.4, available at
|
||||||
|
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see
|
||||||
|
https://www.contributor-covenant.org/faq
|
||||||
135
vendor/github.com/adrg/xdg/CONTRIBUTING.md
generated
vendored
Normal file
135
vendor/github.com/adrg/xdg/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Contributing to this project
|
||||||
|
|
||||||
|
Contributions in the form of pull requests, issues or just general feedback,
|
||||||
|
are always welcome. Please take a moment to review this document in order to
|
||||||
|
make the contribution process easy and effective for everyone involved.
|
||||||
|
|
||||||
|
Following these guidelines helps to communicate that you respect the time of
|
||||||
|
the developers managing and developing this open source project. In return,
|
||||||
|
they should reciprocate that respect in addressing your issue or assessing
|
||||||
|
patches and features.
|
||||||
|
|
||||||
|
## Using the issue tracker
|
||||||
|
|
||||||
|
The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||||
|
[features requests](#features) and [submitting pull
|
||||||
|
requests](#pull-requests), but please respect the following restrictions:
|
||||||
|
|
||||||
|
* Please **do not** use the issue tracker for personal support requests (use
|
||||||
|
[Stack Overflow](http://stackoverflow.com) or IRC).
|
||||||
|
* Please **do not** derail or troll issues. Keep the discussion on topic and
|
||||||
|
respect the opinions of others.
|
||||||
|
|
||||||
|
<a name="bugs"></a>
|
||||||
|
## Bug reports
|
||||||
|
|
||||||
|
A bug is a _demonstrable problem_ that is caused by the code in the repository.
|
||||||
|
Good bug reports are extremely helpful - thank you!
|
||||||
|
|
||||||
|
Guidelines for bug reports:
|
||||||
|
|
||||||
|
1. **Use the GitHub issue search** — check if the issue has already been
|
||||||
|
reported.
|
||||||
|
2. **Check if the issue has been fixed** — try to reproduce it using the
|
||||||
|
latest `master` or development branch in the repository.
|
||||||
|
3. **Isolate the problem** — create a reduced test case.
|
||||||
|
|
||||||
|
A good bug report shouldn't leave others needing to chase you up for more
|
||||||
|
information. Please try to be as detailed as possible in your report. What is
|
||||||
|
your environment? What steps will reproduce the issue? What browser(s) and OS
|
||||||
|
experience the problem? What would you expect to be the outcome? All these
|
||||||
|
details will help people to fix any potential bugs.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
> Short and descriptive example bug report title
|
||||||
|
>
|
||||||
|
> A summary of the issue and the browser/OS environment in which it occurs. If
|
||||||
|
> suitable, include the steps required to reproduce the bug.
|
||||||
|
>
|
||||||
|
> 1. This is the first step
|
||||||
|
> 2. This is the second step
|
||||||
|
> 3. Further steps, etc.
|
||||||
|
>
|
||||||
|
> `<url>` - a link to the reduced test case
|
||||||
|
>
|
||||||
|
> Any other information you want to share that is relevant to the issue being
|
||||||
|
> reported. This might include the lines of code that you have identified as
|
||||||
|
> causing the bug, and potential solutions (and your opinions on their
|
||||||
|
> merits).
|
||||||
|
|
||||||
|
|
||||||
|
<a name="features"></a>
|
||||||
|
## Feature requests
|
||||||
|
|
||||||
|
Feature requests are welcome. But take a moment to find out whether your idea
|
||||||
|
fits with the scope and aims of the project. It's up to *you* to make a strong
|
||||||
|
case to convince the project's developers of the merits of this feature. Please
|
||||||
|
provide as much detail and context as possible.
|
||||||
|
|
||||||
|
|
||||||
|
<a name="pull-requests"></a>
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
Good pull requests - patches, improvements, new features - are a fantastic
|
||||||
|
help. They should remain focused in scope and avoid containing unrelated
|
||||||
|
commits.
|
||||||
|
|
||||||
|
**Please ask first** before embarking on any significant pull request (e.g.
|
||||||
|
implementing features, refactoring code, porting to a different language),
|
||||||
|
otherwise you risk spending a lot of time working on something that the
|
||||||
|
project's developers might not want to merge into the project.
|
||||||
|
|
||||||
|
Please adhere to the coding conventions used throughout a project (indentation,
|
||||||
|
accurate comments, etc.) and any other requirements (such as test coverage).
|
||||||
|
|
||||||
|
Follow this process if you'd like your work considered for inclusion in the
|
||||||
|
project:
|
||||||
|
|
||||||
|
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
|
||||||
|
and configure the remotes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone your fork of the repo into the current directory
|
||||||
|
git clone https://github.com/<your-username>/<repo-name>
|
||||||
|
# Navigate to the newly cloned directory
|
||||||
|
cd <repo-name>
|
||||||
|
# Assign the original repo to a remote called "upstream"
|
||||||
|
git remote add upstream https://github.com/<upstream-owner>/<repo-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If you cloned a while ago, get the latest changes from upstream:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout <dev-branch>
|
||||||
|
git pull upstream <dev-branch>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create a new topic branch (off the main project development branch) to
|
||||||
|
contain your feature, change, or fix:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b <topic-branch-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Commit your changes in logical chunks and use descriptive commit messages.
|
||||||
|
Use [interactive rebase](https://help.github.com/articles/interactive-rebase)
|
||||||
|
to tidy up your commits before making them public.
|
||||||
|
|
||||||
|
5. Locally merge (or rebase) the upstream development branch into your topic branch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull [--rebase] upstream <dev-branch>
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Push your topic branch up to your fork:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push origin <topic-branch-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
|
||||||
|
with a clear title and description.
|
||||||
|
|
||||||
|
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
|
||||||
|
license your work under the same license as that used by the project.
|
||||||
21
vendor/github.com/adrg/xdg/LICENSE
generated
vendored
Normal file
21
vendor/github.com/adrg/xdg/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Adrian-George Bostan <adrg@epistack.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
302
vendor/github.com/adrg/xdg/README.md
generated
vendored
Normal file
302
vendor/github.com/adrg/xdg/README.md
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
<h1 align="center">
|
||||||
|
<div>
|
||||||
|
<img src="https://raw.githubusercontent.com/adrg/adrg.github.io/master/assets/projects/xdg/logo.svg" alt="xdg logo"/>
|
||||||
|
</div>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h4 align="center">Go implementation of the XDG Base Directory Specification and XDG user directories.</h4>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/adrg/xdg/actions/workflows/tests.yml">
|
||||||
|
<img alt="Tests status" src="https://github.com/adrg/xdg/actions/workflows/tests.yml/badge.svg">
|
||||||
|
</a>
|
||||||
|
<a href="https://app.codecov.io/gh/adrg/xdg">
|
||||||
|
<img alt="Code coverage" src="https://codecov.io/gh/adrg/xdg/branch/master/graphs/badge.svg?branch=master">
|
||||||
|
</a>
|
||||||
|
<a href="https://pkg.go.dev/github.com/adrg/xdg">
|
||||||
|
<img alt="pkg.go.dev documentation" src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white">
|
||||||
|
</a>
|
||||||
|
<a href="https://opensource.org/licenses/MIT" rel="nofollow">
|
||||||
|
<img alt="MIT license" src="https://img.shields.io/github/license/adrg/xdg">
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
<a href="https://goreportcard.com/report/github.com/adrg/xdg">
|
||||||
|
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/adrg/xdg">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/avelino/awesome-go#configuration">
|
||||||
|
<img alt="Awesome Go" src="https://awesome.re/mentioned-badge.svg">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/adrg/xdg/graphs/contributors">
|
||||||
|
<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/adrg/xdg" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/adrg/xdg/issues">
|
||||||
|
<img alt="GitHub open issues" src="https://img.shields.io/github/issues-raw/adrg/xdg">
|
||||||
|
</a>
|
||||||
|
<a href="https://ko-fi.com/T6T72WATK">
|
||||||
|
<img alt="Buy me a coffee" src="https://img.shields.io/static/v1.svg?label=%20&message=Buy%20me%20a%20coffee&color=579fbf&logo=buy%20me%20a%20coffee&logoColor=white">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Provides an implementation of the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
|
||||||
|
The specification defines a set of standard paths for storing application files,
|
||||||
|
including data and configuration files. For portability and flexibility reasons,
|
||||||
|
applications should use the XDG defined locations instead of hardcoding paths.
|
||||||
|
|
||||||
|
The package also includes the locations of well known [user directories](https://wiki.archlinux.org/index.php/XDG_user_directories),
|
||||||
|
support for the non-standard `XDG_BIN_HOME` directory, as well as other common directories such as fonts and applications.
|
||||||
|
|
||||||
|
The current implementation supports **most flavors of Unix**, **Windows**, **macOS** and **Plan 9**.
|
||||||
|
On Windows, where XDG environment variables are not usually set, the package uses [Known Folders](https://docs.microsoft.com/en-us/windows/win32/shell/known-folders)
|
||||||
|
as defaults. Therefore, appropriate locations are used for common [folders](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid) which may have been redirected.
|
||||||
|
|
||||||
|
See usage [examples](#usage) below. Full documentation can be found at https://pkg.go.dev/github.com/adrg/xdg.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
go get github.com/adrg/xdg
|
||||||
|
|
||||||
|
## Default locations
|
||||||
|
|
||||||
|
The package defines sensible defaults for XDG variables which are empty or not
|
||||||
|
present in the environment.
|
||||||
|
|
||||||
|
- On Unix-like operating systems, XDG environment variables are typically defined.
|
||||||
|
Appropriate default locations are used for the environment variables which are not set.
|
||||||
|
- On Windows, XDG environment variables are usually not set. If that is the case,
|
||||||
|
the package relies on the appropriate [Known Folders](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
|
||||||
|
Sensible fallback locations are used for the folders which are not set.
|
||||||
|
|
||||||
|
### XDG Base Directory
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Unix-like operating systems</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#xdg-base-directory"><img width="400" height="0"></a> | <a href="#xdg-base-directory"><img width="500" height="0"></a><p>Unix</p> | <a href="#xdg-base-directory"><img width="600" height="0"></a><p>macOS</p> | <a href="#xdg-base-directory"><img width="500" height="0"></a><p>Plan 9</p> |
|
||||||
|
| :------------------------------------------------------------: | :-----------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>XDG_DATA_HOME</b></kbd> | <kbd>~/.local/share</kbd> | <kbd>~/Library/Application Support</kbd> | <kbd>$home/lib</kbd> |
|
||||||
|
| <kbd><b>XDG_DATA_DIRS</b></kbd> | <kbd>/usr/local/share</kbd><br/><kbd>/usr/share</kbd> | <kbd>/Library/Application Support</kbd><kbd>~/.local/share</kbd> | <kbd>/lib</kbd> |
|
||||||
|
| <kbd><b>XDG_CONFIG_HOME</b></kbd> | <kbd>~/.config</kbd> | <kbd>~/Library/Application Support</kbd> | <kbd>$home/lib</kbd> |
|
||||||
|
| <kbd><b>XDG_CONFIG_DIRS</b></kbd> | <kbd>/etc/xdg</kbd> | <kbd>~/Library/Preferences</kbd><br/><kbd>/Library/Application Support</kbd><br/><kbd>/Library/Preferences</kbd><br/><kbd>~/.config</kbd> | <kbd>/lib</kbd> |
|
||||||
|
| <kbd><b>XDG_STATE_HOME</b></kbd> | <kbd>~/.local/state</kbd> | <kbd>~/Library/Application Support</kbd> | <kbd>$home/lib/state</kbd> |
|
||||||
|
| <kbd><b>XDG_CACHE_HOME</b></kbd> | <kbd>~/.cache</kbd> | <kbd>~/Library/Caches</kbd> | <kbd>$home/lib/cache</kbd> |
|
||||||
|
| <kbd><b>XDG_RUNTIME_DIR</b></kbd> | <kbd>/run/user/$UID</kbd> | <kbd>~/Library/Application Support</kbd> | <kbd>/tmp</kbd> |
|
||||||
|
| <kbd><b>XDG_BIN_HOME</b></kbd> | <kbd>~/.local/bin</kbd> | <kbd>~/.local/bin</kbd> | <kbd>$home/bin</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Microsoft Windows</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#xdg-base-directory"><img width="400" height="0"></a> | <a href="#xdg-base-directory"><img width="700" height="0"></a><p>Known Folder(s)</p> | <a href="#xdg-base-directory"><img width="900" height="0"></a><p>Fallback(s)</p> |
|
||||||
|
| :------------------------------------------------------------: | :---------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>XDG_DATA_HOME</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
|
||||||
|
| <kbd><b>XDG_DATA_DIRS</b></kbd> | <kbd>RoamingAppData</kbd><br/><kbd>ProgramData</kbd> | <kbd>%APPADATA%</kbd><br/><kbd>%ProgramData%</kbd> |
|
||||||
|
| <kbd><b>XDG_CONFIG_HOME</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
|
||||||
|
| <kbd><b>XDG_CONFIG_DIRS</b></kbd> | <kbd>ProgramData</kbd><br/><kbd>RoamingAppData</kbd> | <kbd>%ProgramData%</kbd><br/><kbd>%APPDATA%</kbd> |
|
||||||
|
| <kbd><b>XDG_STATE_HOME</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
|
||||||
|
| <kbd><b>XDG_CACHE_HOME</b></kbd> | <kbd>LocalAppData\cache</kbd> | <kbd>%LOCALAPPDATA%\cache</kbd> |
|
||||||
|
| <kbd><b>XDG_RUNTIME_DIR</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
|
||||||
|
| <kbd><b>XDG_BIN_HOME</b></kbd> | <kbd>UserProgramFiles</kbd> | <kbd>%LOCALAPPDATA%\Programs</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### XDG user directories
|
||||||
|
|
||||||
|
XDG user directories environment variables are usually **not** set on most
|
||||||
|
operating systems. However, if they are present in the environment, they take
|
||||||
|
precedence. Appropriate fallback locations are used for the environment
|
||||||
|
variables which are not set.
|
||||||
|
|
||||||
|
- On Unix-like operating systems (except macOS and Plan 9), the package reads the [user-dirs.dirs](https://man.archlinux.org/man/user-dirs.dirs.5.en) config file.
|
||||||
|
- On Windows, the package uses the appropriate [Known Folders](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
|
||||||
|
|
||||||
|
Lastly, default locations are used for any user directories which are not set,
|
||||||
|
as shown in the following tables.
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Unix-like operating systems</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#xdg-user-directories"><img width="500" height="0"></a> | <a href="#xdg-user-directories"><img width="500" height="0"></a><p>Unix</p> | <a href="#xdg-user-directories"><img width="500" height="0"></a><p>macOS</p> | <a href="#xdg-user-directories"><img width="500" height="0"></a><p>Plan 9</p> |
|
||||||
|
| :--------------------------------------------------------------: | :-------------------------------------------------------------------------: | :---------------------------------------------------------------------------: | :---------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>XDG_DESKTOP_DIR</b></kbd> | <kbd>~/Desktop</kbd> | <kbd>~/Desktop</kbd> | <kbd>$home/desktop</kbd> |
|
||||||
|
| <kbd><b>XDG_DOWNLOAD_DIR</b></kbd> | <kbd>~/Downloads</kbd> | <kbd>~/Downloads</kbd> | <kbd>$home/downloads</kbd> |
|
||||||
|
| <kbd><b>XDG_DOCUMENTS_DIR</b></kbd> | <kbd>~/Documents</kbd> | <kbd>~/Documents</kbd> | <kbd>$home/documents</kbd> |
|
||||||
|
| <kbd><b>XDG_MUSIC_DIR</b></kbd> | <kbd>~/Music</kbd> | <kbd>~/Music</kbd> | <kbd>$home/music</kbd> |
|
||||||
|
| <kbd><b>XDG_PICTURES_DIR</b></kbd> | <kbd>~/Pictures</kbd> | <kbd>~/Pictures</kbd> | <kbd>$home/pictures</kbd> |
|
||||||
|
| <kbd><b>XDG_VIDEOS_DIR</b></kbd> | <kbd>~/Videos</kbd> | <kbd>~/Movies</kbd> | <kbd>$home/videos</kbd> |
|
||||||
|
| <kbd><b>XDG_TEMPLATES_DIR</b></kbd> | <kbd>~/Templates</kbd> | <kbd>~/Templates</kbd> | <kbd>$home/templates</kbd> |
|
||||||
|
| <kbd><b>XDG_PUBLICSHARE_DIR</b></kbd> | <kbd>~/Public</kbd> | <kbd>~/Public</kbd> | <kbd>$home/public</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Microsoft Windows</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#xdg-user-directories"><img width="500" height="0"></a> | <a href="#xdg-user-directories"><img width="600" height="0"></a><p>Known Folder(s)</p> | <a href="#xdg-user-directories"><img width="900" height="0"></a><p>Fallback(s)</p> |
|
||||||
|
| :--------------------------------------------------------------: | :-----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>XDG_DESKTOP_DIR</b></kbd> | <kbd>Desktop</kbd> | <kbd>%USERPROFILE%\Desktop</kbd> |
|
||||||
|
| <kbd><b>XDG_DOWNLOAD_DIR</b></kbd> | <kbd>Downloads</kbd> | <kbd>%USERPROFILE%\Downloads</kbd> |
|
||||||
|
| <kbd><b>XDG_DOCUMENTS_DIR</b></kbd> | <kbd>Documents</kbd> | <kbd>%USERPROFILE%\Documents</kbd> |
|
||||||
|
| <kbd><b>XDG_MUSIC_DIR</b></kbd> | <kbd>Music</kbd> | <kbd>%USERPROFILE%\Music</kbd> |
|
||||||
|
| <kbd><b>XDG_PICTURES_DIR</b></kbd> | <kbd>Pictures</kbd> | <kbd>%USERPROFILE%\Pictures</kbd> |
|
||||||
|
| <kbd><b>XDG_VIDEOS_DIR</b></kbd> | <kbd>Videos</kbd> | <kbd>%USERPROFILE%\Videos</kbd> |
|
||||||
|
| <kbd><b>XDG_TEMPLATES_DIR</b></kbd> | <kbd>Templates</kbd> | <kbd>%APPDATA%\Microsoft\Windows\Templates</kbd> |
|
||||||
|
| <kbd><b>XDG_PUBLICSHARE_DIR</b></kbd> | <kbd>Public</kbd> | <kbd>%PUBLIC%</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Other directories
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Unix-like operating systems</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#other-directories"><img width="400" height="0"></a> | <a href="#other-directories"><img width="600" height="0"></a><p>Unix</p> | <a href="#other-directories"><img width="600" height="0"></a><p>macOS</p> | <a href="#other-directories"><img width="400" height="0"></a><p>Plan 9</p> |
|
||||||
|
| :-----------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>Home</b></kbd> | <kbd>$HOME</kbd> | <kbd>$HOME</kbd> | <kbd>$home</kbd> |
|
||||||
|
| <kbd><b>Applications</b></kbd> | <kbd>$XDG_DATA_HOME/applications</kbd><br/><kbd>~/.local/share/applications</kbd><br/><kbd>/usr/local/share/applications</kbd><br/><kbd>/usr/share/applications</kbd><br/><kbd>$XDG_DATA_DIRS/applications</kbd> | <kbd>/Applications</kbd> | <kbd>$home/bin</kbd><br/><kbd>/bin</kbd> |
|
||||||
|
| <kbd><b>Fonts</b></kbd> | <kbd>$XDG_DATA_HOME/fonts</kbd><br/><kbd>~/.fonts</kbd><br/><kbd>~/.local/share/fonts</kbd><br/><kbd>/usr/local/share/fonts</kbd><br/><kbd>/usr/share/fonts</kbd><br/><kbd>$XDG_DATA_DIRS/fonts</kbd> | <kbd>~/Library/Fonts</kbd><br/><kbd>/Library/Fonts</kbd><br/><kbd>/System/Library/Fonts</kbd><br/><kbd>/Network/Library/Fonts</kbd> | <kbd>$home/lib/font</kbd><br/><kbd>/lib/font</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary><strong>Microsoft Windows</strong></summary>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
| <a href="#other-directories"><img width="400" height="0"></a> | <a href="#other-directories"><img width="300" height="0"></a><p>Known Folder(s)</p> | <a href="#other-directories"><img width="1300" height="0"></a><p>Fallback(s)</p> |
|
||||||
|
| :-----------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||||
|
| <kbd><b>Home</b></kbd> | <kbd>Profile</kbd> | <kbd>%USERPROFILE%</kbd> |
|
||||||
|
| <kbd><b>Applications</b></kbd> | <kbd>Programs</kbd><br/><kbd>CommonPrograms</kbd> <br/><kbd>ProgramFiles</kbd><br/><kbd>ProgramFilesCommon</kbd><br/><kbd>UserProgramFiles</kbd><br/><kbd>UserProgramFilesCommon</kbd> | <kbd>%APPDATA%\Microsoft\Windows\Start Menu\Programs</kbd><br/><kbd>%ProgramData%\Microsoft\Windows\Start Menu\Programs</kbd><br/><kbd>%ProgramFiles%</kbd><br/><kbd>%ProgramFiles%\Common Files</kbd><br/><kbd>%LOCALAPPDATA%\Programs</kbd><br/><kbd>%LOCALAPPDATA%\Programs\Common</kbd>|
|
||||||
|
| <kbd><b>Fonts</b></kbd> | <kbd>Fonts</kbd> | <kbd>%SystemRoot%\Fonts</kbd><br/><kbd>%LOCALAPPDATA%\Microsoft\Windows\Fonts</kbd> |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### XDG Base Directory
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// XDG Base Directory paths.
|
||||||
|
log.Println("Home data directory:", xdg.DataHome)
|
||||||
|
log.Println("Data directories:", xdg.DataDirs)
|
||||||
|
log.Println("Home config directory:", xdg.ConfigHome)
|
||||||
|
log.Println("Config directories:", xdg.ConfigDirs)
|
||||||
|
log.Println("Home state directory:", xdg.StateHome)
|
||||||
|
log.Println("Cache directory:", xdg.CacheHome)
|
||||||
|
log.Println("Runtime directory:", xdg.RuntimeDir)
|
||||||
|
log.Println("Home binaries directory:", xdg.BinHome)
|
||||||
|
|
||||||
|
// Other common directories.
|
||||||
|
log.Println("Home directory:", xdg.Home)
|
||||||
|
log.Println("Application directories:", xdg.ApplicationDirs)
|
||||||
|
log.Println("Font directories:", xdg.FontDirs)
|
||||||
|
|
||||||
|
// Obtain a suitable location for application config files.
|
||||||
|
// ConfigFile takes one parameter which must contain the name of the file,
|
||||||
|
// but it can also contain a set of parent directories. If the directories
|
||||||
|
// don't exist, they will be created relative to the base config directory.
|
||||||
|
// It is recommended for files to be saved inside an application directory
|
||||||
|
// relative to the base directory rather than directly inside the base
|
||||||
|
// directory (e.g. `appname/config.yaml` instead of `appname-config.yaml`).
|
||||||
|
configFilePath, err := xdg.ConfigFile("appname/config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Save the config file at:", configFilePath)
|
||||||
|
|
||||||
|
// For other types of application files use:
|
||||||
|
// xdg.DataFile()
|
||||||
|
// xdg.StateFile()
|
||||||
|
// xdg.CacheFile()
|
||||||
|
// xdg.RuntimeFile()
|
||||||
|
|
||||||
|
// Finding application config files.
|
||||||
|
// SearchConfigFile takes one parameter which must contain the name of
|
||||||
|
// the file, but it can also contain a set of parent directories relative
|
||||||
|
// to the config search paths (xdg.ConfigHome and xdg.ConfigDirs).
|
||||||
|
configFilePath, err = xdg.SearchConfigFile("appname/config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Config file was found at:", configFilePath)
|
||||||
|
|
||||||
|
// For other types of application files use:
|
||||||
|
// xdg.SearchDataFile()
|
||||||
|
// xdg.SearchStateFile()
|
||||||
|
// xdg.SearchCacheFile()
|
||||||
|
// xdg.SearchRuntimeFile()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### XDG user directories
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// XDG user directories.
|
||||||
|
log.Println("Desktop directory:", xdg.UserDirs.Desktop)
|
||||||
|
log.Println("Download directory:", xdg.UserDirs.Download)
|
||||||
|
log.Println("Documents directory:", xdg.UserDirs.Documents)
|
||||||
|
log.Println("Music directory:", xdg.UserDirs.Music)
|
||||||
|
log.Println("Pictures directory:", xdg.UserDirs.Pictures)
|
||||||
|
log.Println("Videos directory:", xdg.UserDirs.Videos)
|
||||||
|
log.Println("Templates directory:", xdg.UserDirs.Templates)
|
||||||
|
log.Println("Public directory:", xdg.UserDirs.PublicShare)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Stargazers over time
|
||||||
|
|
||||||
|
[](https://starchart.cc/adrg/xdg)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions in the form of pull requests, issues or just general feedback,
|
||||||
|
are always welcome.
|
||||||
|
See [CONTRIBUTING.MD](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
**Contributors**:
|
||||||
|
[adrg](https://github.com/adrg),
|
||||||
|
[wichert](https://github.com/wichert),
|
||||||
|
[bouncepaw](https://github.com/bouncepaw),
|
||||||
|
[gabriel-vasile](https://github.com/gabriel-vasile),
|
||||||
|
[KalleDK](https://github.com/KalleDK),
|
||||||
|
[nvkv](https://github.com/nvkv),
|
||||||
|
[djdv](https://github.com/djdv),
|
||||||
|
[rrjjvv](https://github.com/rrjjvv),
|
||||||
|
[GreyXor](https://github.com/GreyXor),
|
||||||
|
[Rican7](https://github.com/Rican7),
|
||||||
|
[nothub](https://github.com/nothub).
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
For more information see:
|
||||||
|
* [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
|
||||||
|
* [XDG user directories](https://wiki.archlinux.org/index.php/XDG_user_directories)
|
||||||
|
* [Windows Known Folders](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright (c) 2014 Adrian-George Bostan.
|
||||||
|
|
||||||
|
This project is licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||||
|
See [LICENSE](LICENSE) for more details.
|
||||||
82
vendor/github.com/adrg/xdg/base_dirs.go
generated
vendored
Normal file
82
vendor/github.com/adrg/xdg/base_dirs.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XDG Base Directory environment variables.
|
||||||
|
const (
|
||||||
|
envDataHome = "XDG_DATA_HOME"
|
||||||
|
envDataDirs = "XDG_DATA_DIRS"
|
||||||
|
envConfigHome = "XDG_CONFIG_HOME"
|
||||||
|
envConfigDirs = "XDG_CONFIG_DIRS"
|
||||||
|
envStateHome = "XDG_STATE_HOME"
|
||||||
|
envCacheHome = "XDG_CACHE_HOME"
|
||||||
|
envRuntimeDir = "XDG_RUNTIME_DIR"
|
||||||
|
|
||||||
|
// Non-standard.
|
||||||
|
envBinHome = "XDG_BIN_HOME"
|
||||||
|
)
|
||||||
|
|
||||||
|
type baseDirectories struct {
|
||||||
|
dataHome string
|
||||||
|
data []string
|
||||||
|
configHome string
|
||||||
|
config []string
|
||||||
|
stateHome string
|
||||||
|
cacheHome string
|
||||||
|
runtime string
|
||||||
|
|
||||||
|
// Non-standard.
|
||||||
|
binHome string
|
||||||
|
fonts []string
|
||||||
|
applications []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) dataFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Create(relPath, append([]string{bd.dataHome}, bd.data...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) configFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Create(relPath, append([]string{bd.configHome}, bd.config...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) stateFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Create(relPath, []string{bd.stateHome})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) cacheFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Create(relPath, []string{bd.cacheHome})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) runtimeFile(relPath string) (string, error) {
|
||||||
|
var paths []string
|
||||||
|
for _, p := range pathutil.Unique([]string{bd.runtime, os.TempDir()}) {
|
||||||
|
if pathutil.Exists(p) {
|
||||||
|
paths = append(paths, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pathutil.Create(relPath, paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) searchDataFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Search(relPath, append([]string{bd.dataHome}, bd.data...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) searchConfigFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Search(relPath, append([]string{bd.configHome}, bd.config...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) searchStateFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Search(relPath, []string{bd.stateHome})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) searchCacheFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Search(relPath, []string{bd.cacheHome})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd baseDirectories) searchRuntimeFile(relPath string) (string, error) {
|
||||||
|
return pathutil.Search(relPath, pathutil.Unique([]string{bd.runtime, os.TempDir()}))
|
||||||
|
}
|
||||||
11
vendor/github.com/adrg/xdg/codecov.yml
generated
vendored
Normal file
11
vendor/github.com/adrg/xdg/codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
target: 90%
|
||||||
|
threshold: 1%
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
target: 100%
|
||||||
|
ignore:
|
||||||
|
- "paths_plan9.go"
|
||||||
105
vendor/github.com/adrg/xdg/doc.go
generated
vendored
Normal file
105
vendor/github.com/adrg/xdg/doc.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Package xdg provides an implementation of the XDG Base Directory Specification.
|
||||||
|
The specification defines a set of standard paths for storing application files
|
||||||
|
including data and configuration files. For portability and flexibility reasons,
|
||||||
|
applications should use the XDG defined locations instead of hardcoding paths.
|
||||||
|
The package also includes the locations of well known user directories.
|
||||||
|
|
||||||
|
The current implementation supports most flavors of Unix, Windows, Mac OS and Plan 9.
|
||||||
|
|
||||||
|
For more information regarding the XDG Base Directory Specification see:
|
||||||
|
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||||
|
|
||||||
|
For more information regarding the XDG user directories see:
|
||||||
|
https://wiki.archlinux.org/index.php/XDG_user_directories
|
||||||
|
|
||||||
|
For more information regarding the Windows Known Folders see:
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/shell/known-folders
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
XDG Base Directory
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// XDG Base Directory paths.
|
||||||
|
log.Println("Home data directory:", xdg.DataHome)
|
||||||
|
log.Println("Data directories:", xdg.DataDirs)
|
||||||
|
log.Println("Home config directory:", xdg.ConfigHome)
|
||||||
|
log.Println("Config directories:", xdg.ConfigDirs)
|
||||||
|
log.Println("Home state directory:", xdg.StateHome)
|
||||||
|
log.Println("Cache directory:", xdg.CacheHome)
|
||||||
|
log.Println("Runtime directory:", xdg.RuntimeDir)
|
||||||
|
log.Println("Home binaries directory:", xdg.BinHome)
|
||||||
|
|
||||||
|
// Other common directories.
|
||||||
|
log.Println("Home directory:", xdg.Home)
|
||||||
|
log.Println("Application directories:", xdg.ApplicationDirs)
|
||||||
|
log.Println("Font directories:", xdg.FontDirs)
|
||||||
|
|
||||||
|
// Obtain a suitable location for application config files.
|
||||||
|
// ConfigFile takes one parameter which must contain the name of the file,
|
||||||
|
// but it can also contain a set of parent directories. If the directories
|
||||||
|
// don't exist, they will be created relative to the base config directory.
|
||||||
|
// It is recommended for files to be saved inside an application directory
|
||||||
|
// relative to the base directory rather than directly inside the base
|
||||||
|
// directory (e.g. `appname/config.yaml` instead of `appname-config.yaml`).
|
||||||
|
configFilePath, err := xdg.ConfigFile("appname/config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Save the config file at:", configFilePath)
|
||||||
|
|
||||||
|
// For other types of application files use:
|
||||||
|
// xdg.DataFile()
|
||||||
|
// xdg.StateFile()
|
||||||
|
// xdg.CacheFile()
|
||||||
|
// xdg.RuntimeFile()
|
||||||
|
|
||||||
|
// Finding application config files.
|
||||||
|
// SearchConfigFile takes one parameter which must contain the name of
|
||||||
|
// the file, but it can also contain a set of parent directories relative
|
||||||
|
// to the config search paths (xdg.ConfigHome and xdg.ConfigDirs).
|
||||||
|
configFilePath, err = xdg.SearchConfigFile("appname/config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Config file was found at:", configFilePath)
|
||||||
|
|
||||||
|
// For other types of application files use:
|
||||||
|
// xdg.SearchDataFile()
|
||||||
|
// xdg.SearchStateFile()
|
||||||
|
// xdg.SearchCacheFile()
|
||||||
|
// xdg.SearchRuntimeFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
XDG user directories
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// XDG user directories.
|
||||||
|
log.Println("Desktop directory:", xdg.UserDirs.Desktop)
|
||||||
|
log.Println("Download directory:", xdg.UserDirs.Download)
|
||||||
|
log.Println("Documents directory:", xdg.UserDirs.Documents)
|
||||||
|
log.Println("Music directory:", xdg.UserDirs.Music)
|
||||||
|
log.Println("Pictures directory:", xdg.UserDirs.Pictures)
|
||||||
|
log.Println("Videos directory:", xdg.UserDirs.Videos)
|
||||||
|
log.Println("Templates directory:", xdg.UserDirs.Templates)
|
||||||
|
log.Println("Public directory:", xdg.UserDirs.PublicShare)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package xdg
|
||||||
114
vendor/github.com/adrg/xdg/internal/pathutil/pathutil.go
generated
vendored
Normal file
114
vendor/github.com/adrg/xdg/internal/pathutil/pathutil.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package pathutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unique eliminates the duplicate paths from the provided slice and returns
|
||||||
|
// the result. The paths are expanded using the `ExpandHome` function and only
|
||||||
|
// absolute paths are kept. The items in the output slice are in the order in
|
||||||
|
// which they occur in the input slice.
|
||||||
|
func Unique(paths []string) []string {
|
||||||
|
var (
|
||||||
|
uniq []string
|
||||||
|
registry = map[string]struct{}{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, p := range paths {
|
||||||
|
if p = ExpandHome(p); p != "" && filepath.IsAbs(p) {
|
||||||
|
if _, ok := registry[p]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
registry[p] = struct{}{}
|
||||||
|
uniq = append(uniq, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniq
|
||||||
|
}
|
||||||
|
|
||||||
|
// First returns the first absolute path from the provided slice.
|
||||||
|
// The paths in the input slice are expanded using the `ExpandHome` function.
|
||||||
|
func First(paths []string) string {
|
||||||
|
for _, p := range paths {
|
||||||
|
if p = ExpandHome(p); p != "" && filepath.IsAbs(p) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create returns a suitable location relative to which the file with the
|
||||||
|
// specified `name` can be written. The first path from the provided `paths`
|
||||||
|
// slice which is successfully created (or already exists) is used as a base
|
||||||
|
// path for the file. The `name` parameter should contain the name of the file
|
||||||
|
// which is going to be written in the location returned by this function, but
|
||||||
|
// it can also contain a set of parent directories, which will be created
|
||||||
|
// relative to the selected parent path.
|
||||||
|
func Create(name string, paths []string) (string, error) {
|
||||||
|
searchedPaths := make([]string, 0, len(paths))
|
||||||
|
for _, p := range paths {
|
||||||
|
p = filepath.Join(p, name)
|
||||||
|
|
||||||
|
dir := filepath.Dir(p)
|
||||||
|
if Exists(dir) {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(dir, os.ModeDir|0o700); err == nil {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
searchedPaths = append(searchedPaths, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("could not create any of the following paths: %v",
|
||||||
|
searchedPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search searches for the file with the specified `name` in the provided
|
||||||
|
// slice of `paths`. The `name` parameter must contain the name of the file,
|
||||||
|
// but it can also contain a set of parent directories.
|
||||||
|
func Search(name string, paths []string) (string, error) {
|
||||||
|
searchedPaths := make([]string, 0, len(paths))
|
||||||
|
for _, p := range paths {
|
||||||
|
p = filepath.Join(p, name)
|
||||||
|
if Exists(p) {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
searchedPaths = append(searchedPaths, filepath.Dir(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("could not locate `%s` in any of the following paths: %v",
|
||||||
|
filepath.Base(name), searchedPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvPath returns the value of the environment variable with the specified
|
||||||
|
// `name` if it is an absolute path, or the first absolute fallback path.
|
||||||
|
// All paths are expanded using the `ExpandHome` function.
|
||||||
|
func EnvPath(name string, fallbackPaths ...string) string {
|
||||||
|
dir := ExpandHome(os.Getenv(name))
|
||||||
|
if dir != "" && filepath.IsAbs(dir) {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
return First(fallbackPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvPathList reads the value of the environment variable with the specified
|
||||||
|
// `name` and attempts to extract a list of absolute paths from it. If there
|
||||||
|
// are none, a list of absolute fallback paths is returned instead. Duplicate
|
||||||
|
// paths are removed from the returned slice. All paths are expanded using the
|
||||||
|
// `ExpandHome` function.
|
||||||
|
func EnvPathList(name string, fallbackPaths ...string) []string {
|
||||||
|
dirs := Unique(filepath.SplitList(os.Getenv(name)))
|
||||||
|
if len(dirs) != 0 {
|
||||||
|
return dirs
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unique(fallbackPaths)
|
||||||
|
}
|
||||||
40
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_plan9.go
generated
vendored
Normal file
40
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_plan9.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package pathutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserHomeDir returns the home directory of the current user.
|
||||||
|
func UserHomeDir() string {
|
||||||
|
if home := os.Getenv("home"); home != "" {
|
||||||
|
return home
|
||||||
|
}
|
||||||
|
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists returns true if the specified path exists.
|
||||||
|
func Exists(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err == nil || errors.Is(err, fs.ErrExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandHome substitutes `~` and `$home` at the start of the specified `path`.
|
||||||
|
func ExpandHome(path string) string {
|
||||||
|
home := UserHomeDir()
|
||||||
|
if path == "" || home == "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
if path[0] == '~' {
|
||||||
|
return filepath.Join(home, path[1:])
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(path, "$home") {
|
||||||
|
return filepath.Join(home, path[5:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
42
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_unix.go
generated
vendored
Normal file
42
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_unix.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || nacl || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package pathutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserHomeDir returns the home directory of the current user.
|
||||||
|
func UserHomeDir() string {
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
return home
|
||||||
|
}
|
||||||
|
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists returns true if the specified path exists.
|
||||||
|
func Exists(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err == nil || errors.Is(err, fs.ErrExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandHome substitutes `~` and `$HOME` at the start of the specified `path`.
|
||||||
|
func ExpandHome(path string) string {
|
||||||
|
home := UserHomeDir()
|
||||||
|
if path == "" || home == "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
if path[0] == '~' {
|
||||||
|
return filepath.Join(home, path[1:])
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(path, "$HOME") {
|
||||||
|
return filepath.Join(home, path[5:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
71
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_windows.go
generated
vendored
Normal file
71
vendor/github.com/adrg/xdg/internal/pathutil/pathutil_windows.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package pathutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserHomeDir returns the home directory of the current user.
|
||||||
|
func UserHomeDir() string {
|
||||||
|
return KnownFolder(windows.FOLDERID_Profile, []string{"USERPROFILE"}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists returns true if the specified path exists.
|
||||||
|
func Exists(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if fi != nil && fi.Mode()&os.ModeSymlink != 0 {
|
||||||
|
_, err = filepath.EvalSymlinks(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err == nil || errors.Is(err, fs.ErrExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpandHome substitutes `%USERPROFILE%` at the start of the specified `path`.
|
||||||
|
func ExpandHome(path string) string {
|
||||||
|
home := UserHomeDir()
|
||||||
|
if path == "" || home == "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(path, `%USERPROFILE%`) {
|
||||||
|
return filepath.Join(home, path[13:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// KnownFolder returns the location of the folder with the specified ID.
|
||||||
|
// If that fails, the folder location is determined by reading the provided
|
||||||
|
// environment variables (the first non-empty read value is returned).
|
||||||
|
// If that fails as well, the first non-empty fallback is returned.
|
||||||
|
// If all of the above fails, the function returns an empty string.
|
||||||
|
func KnownFolder(id *windows.KNOWNFOLDERID, envVars []string, fallbacks []string) string {
|
||||||
|
if id != nil {
|
||||||
|
flags := []uint32{windows.KF_FLAG_DEFAULT, windows.KF_FLAG_DEFAULT_PATH}
|
||||||
|
for _, flag := range flags {
|
||||||
|
p, _ := windows.KnownFolderPath(id, flag|windows.KF_FLAG_DONT_VERIFY)
|
||||||
|
if p != "" {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, envVar := range envVars {
|
||||||
|
p := os.Getenv(envVar)
|
||||||
|
if p != "" {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fallback := range fallbacks {
|
||||||
|
if fallback != "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
82
vendor/github.com/adrg/xdg/internal/userdirs/config_unix.go
generated
vendored
Normal file
82
vendor/github.com/adrg/xdg/internal/userdirs/config_unix.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
//go:build aix || dragonfly || freebsd || (js && wasm) || nacl || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package userdirs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseConfigFile parses the user directories config file at the
|
||||||
|
// specified location.
|
||||||
|
func ParseConfigFile(name string) (*Directories, error) {
|
||||||
|
f, err := os.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return ParseConfig(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseConfig parses the user directories config file contained in
|
||||||
|
// the provided reader.
|
||||||
|
func ParseConfig(r io.Reader) (*Directories, error) {
|
||||||
|
dirs := &Directories{}
|
||||||
|
fieldsMap := map[string]*string{
|
||||||
|
EnvDesktopDir: &dirs.Desktop,
|
||||||
|
EnvDownloadDir: &dirs.Download,
|
||||||
|
EnvDocumentsDir: &dirs.Documents,
|
||||||
|
EnvMusicDir: &dirs.Music,
|
||||||
|
EnvPicturesDir: &dirs.Pictures,
|
||||||
|
EnvVideosDir: &dirs.Videos,
|
||||||
|
EnvTemplatesDir: &dirs.Templates,
|
||||||
|
EnvPublicShareDir: &dirs.PublicShare,
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if len(line) == 0 || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(line, "XDG_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(line, "=")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse key.
|
||||||
|
field, ok := fieldsMap[strings.TrimSpace(parts[0])]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse value.
|
||||||
|
runes := []rune(strings.TrimSpace(parts[1]))
|
||||||
|
|
||||||
|
lenRunes := len(runes)
|
||||||
|
if lenRunes <= 2 || runes[0] != '"' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < lenRunes; i++ {
|
||||||
|
if runes[i] == '"' {
|
||||||
|
*field = pathutil.ExpandHome(string(runes[1:i]))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirs, nil
|
||||||
|
}
|
||||||
40
vendor/github.com/adrg/xdg/internal/userdirs/userdirs.go
generated
vendored
Normal file
40
vendor/github.com/adrg/xdg/internal/userdirs/userdirs.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package userdirs
|
||||||
|
|
||||||
|
// XDG user directories environment variables.
|
||||||
|
const (
|
||||||
|
EnvDesktopDir = "XDG_DESKTOP_DIR"
|
||||||
|
EnvDownloadDir = "XDG_DOWNLOAD_DIR"
|
||||||
|
EnvDocumentsDir = "XDG_DOCUMENTS_DIR"
|
||||||
|
EnvMusicDir = "XDG_MUSIC_DIR"
|
||||||
|
EnvPicturesDir = "XDG_PICTURES_DIR"
|
||||||
|
EnvVideosDir = "XDG_VIDEOS_DIR"
|
||||||
|
EnvTemplatesDir = "XDG_TEMPLATES_DIR"
|
||||||
|
EnvPublicShareDir = "XDG_PUBLICSHARE_DIR"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Directories defines the locations of well known user directories.
|
||||||
|
type Directories struct {
|
||||||
|
// Desktop defines the location of the user's desktop directory.
|
||||||
|
Desktop string
|
||||||
|
|
||||||
|
// Download defines a suitable location for user downloaded files.
|
||||||
|
Download string
|
||||||
|
|
||||||
|
// Documents defines a suitable location for user document files.
|
||||||
|
Documents string
|
||||||
|
|
||||||
|
// Music defines a suitable location for user audio files.
|
||||||
|
Music string
|
||||||
|
|
||||||
|
// Pictures defines a suitable location for user image files.
|
||||||
|
Pictures string
|
||||||
|
|
||||||
|
// VideosDir defines a suitable location for user video files.
|
||||||
|
Videos string
|
||||||
|
|
||||||
|
// Templates defines a suitable location for user template files.
|
||||||
|
Templates string
|
||||||
|
|
||||||
|
// PublicShare defines a suitable location for user shared files.
|
||||||
|
PublicShare string
|
||||||
|
}
|
||||||
60
vendor/github.com/adrg/xdg/paths_darwin.go
generated
vendored
Normal file
60
vendor/github.com/adrg/xdg/paths_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
"github.com/adrg/xdg/internal/userdirs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initDirs(home string) {
|
||||||
|
initBaseDirs(home)
|
||||||
|
initUserDirs(home)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBaseDirs(home string) {
|
||||||
|
homeAppSupport := filepath.Join(home, "Library", "Application Support")
|
||||||
|
rootAppSupport := "/Library/Application Support"
|
||||||
|
|
||||||
|
// Initialize standard directories.
|
||||||
|
baseDirs.dataHome = pathutil.EnvPath(envDataHome, homeAppSupport)
|
||||||
|
baseDirs.data = pathutil.EnvPathList(envDataDirs,
|
||||||
|
rootAppSupport,
|
||||||
|
filepath.Join(home, ".local", "share"),
|
||||||
|
)
|
||||||
|
baseDirs.configHome = pathutil.EnvPath(envConfigHome, homeAppSupport)
|
||||||
|
baseDirs.config = pathutil.EnvPathList(envConfigDirs,
|
||||||
|
filepath.Join(home, "Library", "Preferences"),
|
||||||
|
rootAppSupport,
|
||||||
|
"/Library/Preferences",
|
||||||
|
filepath.Join(home, ".config"),
|
||||||
|
)
|
||||||
|
baseDirs.stateHome = pathutil.EnvPath(envStateHome, homeAppSupport)
|
||||||
|
baseDirs.cacheHome = pathutil.EnvPath(envCacheHome, filepath.Join(home, "Library", "Caches"))
|
||||||
|
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, homeAppSupport)
|
||||||
|
|
||||||
|
// Initialize non-standard directories.
|
||||||
|
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, ".local", "bin"))
|
||||||
|
|
||||||
|
baseDirs.applications = []string{
|
||||||
|
"/Applications",
|
||||||
|
}
|
||||||
|
|
||||||
|
baseDirs.fonts = []string{
|
||||||
|
filepath.Join(home, "Library/Fonts"),
|
||||||
|
"/Library/Fonts",
|
||||||
|
"/System/Library/Fonts",
|
||||||
|
"/Network/Library/Fonts",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUserDirs(home string) {
|
||||||
|
UserDirs.Desktop = pathutil.EnvPath(userdirs.EnvDesktopDir, filepath.Join(home, "Desktop"))
|
||||||
|
UserDirs.Download = pathutil.EnvPath(userdirs.EnvDownloadDir, filepath.Join(home, "Downloads"))
|
||||||
|
UserDirs.Documents = pathutil.EnvPath(userdirs.EnvDocumentsDir, filepath.Join(home, "Documents"))
|
||||||
|
UserDirs.Music = pathutil.EnvPath(userdirs.EnvMusicDir, filepath.Join(home, "Music"))
|
||||||
|
UserDirs.Pictures = pathutil.EnvPath(userdirs.EnvPicturesDir, filepath.Join(home, "Pictures"))
|
||||||
|
UserDirs.Videos = pathutil.EnvPath(userdirs.EnvVideosDir, filepath.Join(home, "Movies"))
|
||||||
|
UserDirs.Templates = pathutil.EnvPath(userdirs.EnvTemplatesDir, filepath.Join(home, "Templates"))
|
||||||
|
UserDirs.PublicShare = pathutil.EnvPath(userdirs.EnvPublicShareDir, filepath.Join(home, "Public"))
|
||||||
|
}
|
||||||
51
vendor/github.com/adrg/xdg/paths_plan9.go
generated
vendored
Normal file
51
vendor/github.com/adrg/xdg/paths_plan9.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
"github.com/adrg/xdg/internal/userdirs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initDirs(home string) {
|
||||||
|
initBaseDirs(home)
|
||||||
|
initUserDirs(home)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBaseDirs(home string) {
|
||||||
|
homeLibDir := filepath.Join(home, "lib")
|
||||||
|
rootLibDir := "/lib"
|
||||||
|
|
||||||
|
// Initialize standard directories.
|
||||||
|
baseDirs.dataHome = pathutil.EnvPath(envDataHome, homeLibDir)
|
||||||
|
baseDirs.data = pathutil.EnvPathList(envDataDirs, rootLibDir)
|
||||||
|
baseDirs.configHome = pathutil.EnvPath(envConfigHome, homeLibDir)
|
||||||
|
baseDirs.config = pathutil.EnvPathList(envConfigDirs, rootLibDir)
|
||||||
|
baseDirs.stateHome = pathutil.EnvPath(envStateHome, filepath.Join(homeLibDir, "state"))
|
||||||
|
baseDirs.cacheHome = pathutil.EnvPath(envCacheHome, filepath.Join(homeLibDir, "cache"))
|
||||||
|
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, "/tmp")
|
||||||
|
|
||||||
|
// Initialize non-standard directories.
|
||||||
|
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, "bin"))
|
||||||
|
|
||||||
|
baseDirs.applications = []string{
|
||||||
|
filepath.Join(home, "bin"),
|
||||||
|
"/bin",
|
||||||
|
}
|
||||||
|
|
||||||
|
baseDirs.fonts = []string{
|
||||||
|
filepath.Join(homeLibDir, "font"),
|
||||||
|
"/lib/font",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUserDirs(home string) {
|
||||||
|
UserDirs.Desktop = pathutil.EnvPath(userdirs.EnvDesktopDir, filepath.Join(home, "desktop"))
|
||||||
|
UserDirs.Download = pathutil.EnvPath(userdirs.EnvDownloadDir, filepath.Join(home, "downloads"))
|
||||||
|
UserDirs.Documents = pathutil.EnvPath(userdirs.EnvDocumentsDir, filepath.Join(home, "documents"))
|
||||||
|
UserDirs.Music = pathutil.EnvPath(userdirs.EnvMusicDir, filepath.Join(home, "music"))
|
||||||
|
UserDirs.Pictures = pathutil.EnvPath(userdirs.EnvPicturesDir, filepath.Join(home, "pictures"))
|
||||||
|
UserDirs.Videos = pathutil.EnvPath(userdirs.EnvVideosDir, filepath.Join(home, "videos"))
|
||||||
|
UserDirs.Templates = pathutil.EnvPath(userdirs.EnvTemplatesDir, filepath.Join(home, "templates"))
|
||||||
|
UserDirs.PublicShare = pathutil.EnvPath(userdirs.EnvPublicShareDir, filepath.Join(home, "public"))
|
||||||
|
}
|
||||||
70
vendor/github.com/adrg/xdg/paths_unix.go
generated
vendored
Normal file
70
vendor/github.com/adrg/xdg/paths_unix.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
//go:build aix || dragonfly || freebsd || (js && wasm) || nacl || linux || netbsd || openbsd || solaris
|
||||||
|
|
||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
"github.com/adrg/xdg/internal/userdirs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initDirs(home string) {
|
||||||
|
initBaseDirs(home)
|
||||||
|
initUserDirs(home, baseDirs.configHome)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBaseDirs(home string) {
|
||||||
|
// Initialize standard directories.
|
||||||
|
baseDirs.dataHome = pathutil.EnvPath(envDataHome, filepath.Join(home, ".local", "share"))
|
||||||
|
baseDirs.data = pathutil.EnvPathList(envDataDirs, "/usr/local/share", "/usr/share")
|
||||||
|
baseDirs.configHome = pathutil.EnvPath(envConfigHome, filepath.Join(home, ".config"))
|
||||||
|
baseDirs.config = pathutil.EnvPathList(envConfigDirs, "/etc/xdg")
|
||||||
|
baseDirs.stateHome = pathutil.EnvPath(envStateHome, filepath.Join(home, ".local", "state"))
|
||||||
|
baseDirs.cacheHome = pathutil.EnvPath(envCacheHome, filepath.Join(home, ".cache"))
|
||||||
|
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, filepath.Join("/run/user", strconv.Itoa(os.Getuid())))
|
||||||
|
|
||||||
|
// Initialize non-standard directories.
|
||||||
|
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, ".local", "bin"))
|
||||||
|
|
||||||
|
appDirs := []string{
|
||||||
|
filepath.Join(baseDirs.dataHome, "applications"),
|
||||||
|
filepath.Join(home, ".local/share/applications"),
|
||||||
|
"/usr/local/share/applications",
|
||||||
|
"/usr/share/applications",
|
||||||
|
}
|
||||||
|
|
||||||
|
fontDirs := []string{
|
||||||
|
filepath.Join(baseDirs.dataHome, "fonts"),
|
||||||
|
filepath.Join(home, ".fonts"),
|
||||||
|
filepath.Join(home, ".local/share/fonts"),
|
||||||
|
"/usr/local/share/fonts",
|
||||||
|
"/usr/share/fonts",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dir := range baseDirs.data {
|
||||||
|
appDirs = append(appDirs, filepath.Join(dir, "applications"))
|
||||||
|
fontDirs = append(fontDirs, filepath.Join(dir, "fonts"))
|
||||||
|
}
|
||||||
|
|
||||||
|
baseDirs.applications = pathutil.Unique(appDirs)
|
||||||
|
baseDirs.fonts = pathutil.Unique(fontDirs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUserDirs(home, configHome string) {
|
||||||
|
dirs, err := userdirs.ParseConfigFile(filepath.Join(configHome, "user-dirs.dirs"))
|
||||||
|
if err != nil {
|
||||||
|
dirs = &UserDirectories{}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserDirs.Desktop = pathutil.EnvPath(userdirs.EnvDesktopDir, dirs.Desktop, filepath.Join(home, "Desktop"))
|
||||||
|
UserDirs.Download = pathutil.EnvPath(userdirs.EnvDownloadDir, dirs.Download, filepath.Join(home, "Downloads"))
|
||||||
|
UserDirs.Documents = pathutil.EnvPath(userdirs.EnvDocumentsDir, dirs.Documents, filepath.Join(home, "Documents"))
|
||||||
|
UserDirs.Music = pathutil.EnvPath(userdirs.EnvMusicDir, dirs.Music, filepath.Join(home, "Music"))
|
||||||
|
UserDirs.Pictures = pathutil.EnvPath(userdirs.EnvPicturesDir, dirs.Pictures, filepath.Join(home, "Pictures"))
|
||||||
|
UserDirs.Videos = pathutil.EnvPath(userdirs.EnvVideosDir, dirs.Videos, filepath.Join(home, "Videos"))
|
||||||
|
UserDirs.Templates = pathutil.EnvPath(userdirs.EnvTemplatesDir, dirs.Templates, filepath.Join(home, "Templates"))
|
||||||
|
UserDirs.PublicShare = pathutil.EnvPath(userdirs.EnvPublicShareDir, dirs.PublicShare, filepath.Join(home, "Public"))
|
||||||
|
}
|
||||||
196
vendor/github.com/adrg/xdg/paths_windows.go
generated
vendored
Normal file
196
vendor/github.com/adrg/xdg/paths_windows.go
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
"github.com/adrg/xdg/internal/userdirs"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initDirs(home string) {
|
||||||
|
kf := initKnownFolders(home)
|
||||||
|
initBaseDirs(home, kf)
|
||||||
|
initUserDirs(home, kf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBaseDirs(home string, kf *knownFolders) {
|
||||||
|
// Initialize standard directories.
|
||||||
|
baseDirs.dataHome = pathutil.EnvPath(envDataHome, kf.localAppData)
|
||||||
|
baseDirs.data = pathutil.EnvPathList(envDataDirs, kf.roamingAppData, kf.programData)
|
||||||
|
baseDirs.configHome = pathutil.EnvPath(envConfigHome, kf.localAppData)
|
||||||
|
baseDirs.config = pathutil.EnvPathList(envConfigDirs, kf.programData, kf.roamingAppData)
|
||||||
|
baseDirs.stateHome = pathutil.EnvPath(envStateHome, kf.localAppData)
|
||||||
|
baseDirs.cacheHome = pathutil.EnvPath(envCacheHome, filepath.Join(kf.localAppData, "cache"))
|
||||||
|
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, kf.localAppData)
|
||||||
|
|
||||||
|
// Initialize non-standard directories.
|
||||||
|
baseDirs.binHome = pathutil.EnvPath(envBinHome, kf.userProgramFiles)
|
||||||
|
|
||||||
|
baseDirs.applications = []string{
|
||||||
|
kf.programs,
|
||||||
|
kf.commonPrograms,
|
||||||
|
kf.programFiles,
|
||||||
|
kf.programFilesCommon,
|
||||||
|
kf.userProgramFiles,
|
||||||
|
kf.userProgramFilesCommon,
|
||||||
|
}
|
||||||
|
|
||||||
|
baseDirs.fonts = []string{
|
||||||
|
kf.fonts,
|
||||||
|
filepath.Join(kf.localAppData, "Microsoft", "Windows", "Fonts"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUserDirs(home string, kf *knownFolders) {
|
||||||
|
UserDirs.Desktop = pathutil.EnvPath(userdirs.EnvDesktopDir, kf.desktop)
|
||||||
|
UserDirs.Download = pathutil.EnvPath(userdirs.EnvDownloadDir, kf.downloads)
|
||||||
|
UserDirs.Documents = pathutil.EnvPath(userdirs.EnvDocumentsDir, kf.documents)
|
||||||
|
UserDirs.Music = pathutil.EnvPath(userdirs.EnvMusicDir, kf.music)
|
||||||
|
UserDirs.Pictures = pathutil.EnvPath(userdirs.EnvPicturesDir, kf.pictures)
|
||||||
|
UserDirs.Videos = pathutil.EnvPath(userdirs.EnvVideosDir, kf.videos)
|
||||||
|
UserDirs.Templates = pathutil.EnvPath(userdirs.EnvTemplatesDir, kf.templates)
|
||||||
|
UserDirs.PublicShare = pathutil.EnvPath(userdirs.EnvPublicShareDir, kf.public)
|
||||||
|
}
|
||||||
|
|
||||||
|
type knownFolders struct {
|
||||||
|
systemDrive string
|
||||||
|
systemRoot string
|
||||||
|
programData string
|
||||||
|
userProfile string
|
||||||
|
userProfiles string
|
||||||
|
roamingAppData string
|
||||||
|
localAppData string
|
||||||
|
desktop string
|
||||||
|
downloads string
|
||||||
|
documents string
|
||||||
|
music string
|
||||||
|
pictures string
|
||||||
|
videos string
|
||||||
|
templates string
|
||||||
|
public string
|
||||||
|
fonts string
|
||||||
|
programs string
|
||||||
|
commonPrograms string
|
||||||
|
programFiles string
|
||||||
|
programFilesCommon string
|
||||||
|
userProgramFiles string
|
||||||
|
userProgramFilesCommon string
|
||||||
|
}
|
||||||
|
|
||||||
|
func initKnownFolders(home string) *knownFolders {
|
||||||
|
kf := &knownFolders{
|
||||||
|
userProfile: home,
|
||||||
|
}
|
||||||
|
kf.systemDrive = filepath.VolumeName(pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Windows,
|
||||||
|
[]string{"SystemDrive", "SystemRoot", "windir"},
|
||||||
|
[]string{home, `C:`},
|
||||||
|
)) + string(filepath.Separator)
|
||||||
|
kf.systemRoot = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Windows,
|
||||||
|
[]string{"SystemRoot", "windir"},
|
||||||
|
[]string{filepath.Join(kf.systemDrive, "Windows")},
|
||||||
|
)
|
||||||
|
kf.programData = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_ProgramData,
|
||||||
|
[]string{"ProgramData", "ALLUSERSPROFILE"},
|
||||||
|
[]string{filepath.Join(kf.systemDrive, "ProgramData")},
|
||||||
|
)
|
||||||
|
kf.userProfiles = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_UserProfiles,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.systemDrive, "Users")},
|
||||||
|
)
|
||||||
|
kf.roamingAppData = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_RoamingAppData,
|
||||||
|
[]string{"APPDATA"},
|
||||||
|
[]string{filepath.Join(home, "AppData", "Roaming")},
|
||||||
|
)
|
||||||
|
kf.localAppData = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_LocalAppData,
|
||||||
|
[]string{"LOCALAPPDATA"},
|
||||||
|
[]string{filepath.Join(home, "AppData", "Local")},
|
||||||
|
)
|
||||||
|
kf.desktop = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Desktop,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Desktop")},
|
||||||
|
)
|
||||||
|
kf.downloads = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Downloads,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Downloads")},
|
||||||
|
)
|
||||||
|
kf.documents = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Documents,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Documents")},
|
||||||
|
)
|
||||||
|
kf.music = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Music,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Music")},
|
||||||
|
)
|
||||||
|
kf.pictures = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Pictures,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Pictures")},
|
||||||
|
)
|
||||||
|
kf.videos = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Videos,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(home, "Videos")},
|
||||||
|
)
|
||||||
|
kf.templates = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Templates,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.roamingAppData, "Microsoft", "Windows", "Templates")},
|
||||||
|
)
|
||||||
|
kf.public = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Public,
|
||||||
|
[]string{"PUBLIC"},
|
||||||
|
[]string{filepath.Join(kf.userProfiles, "Public")},
|
||||||
|
)
|
||||||
|
kf.fonts = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Fonts,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.systemRoot, "Fonts")},
|
||||||
|
)
|
||||||
|
kf.programs = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_Programs,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.roamingAppData, "Microsoft", "Windows", "Start Menu", "Programs")},
|
||||||
|
)
|
||||||
|
kf.commonPrograms = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_CommonPrograms,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.programData, "Microsoft", "Windows", "Start Menu", "Programs")},
|
||||||
|
)
|
||||||
|
kf.programFiles = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_ProgramFiles,
|
||||||
|
[]string{"ProgramFiles"},
|
||||||
|
[]string{filepath.Join(kf.systemDrive, "Program Files")},
|
||||||
|
)
|
||||||
|
kf.programFilesCommon = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_ProgramFilesCommon,
|
||||||
|
nil,
|
||||||
|
[]string{filepath.Join(kf.programFiles, "Common Files")},
|
||||||
|
)
|
||||||
|
kf.userProgramFiles = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_UserProgramFiles,
|
||||||
|
nil,
|
||||||
|
[]string{
|
||||||
|
filepath.Join(kf.localAppData, "Programs"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
kf.userProgramFilesCommon = pathutil.KnownFolder(
|
||||||
|
windows.FOLDERID_UserProgramFilesCommon,
|
||||||
|
nil,
|
||||||
|
[]string{
|
||||||
|
filepath.Join(kf.userProgramFiles, "Common"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return kf
|
||||||
|
}
|
||||||
212
vendor/github.com/adrg/xdg/xdg.go
generated
vendored
Normal file
212
vendor/github.com/adrg/xdg/xdg.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
package xdg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/adrg/xdg/internal/pathutil"
|
||||||
|
"github.com/adrg/xdg/internal/userdirs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserDirectories defines the locations of well known user directories.
|
||||||
|
type UserDirectories = userdirs.Directories
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Home contains the path of the user's home directory.
|
||||||
|
Home string
|
||||||
|
|
||||||
|
// DataHome defines the base directory relative to which user-specific
|
||||||
|
// data files should be stored. This directory is defined by the
|
||||||
|
// $XDG_DATA_HOME environment variable. If the variable is not set,
|
||||||
|
// a default equal to $HOME/.local/share should be used.
|
||||||
|
DataHome string
|
||||||
|
|
||||||
|
// DataDirs defines the preference-ordered set of base directories to
|
||||||
|
// search for data files in addition to the DataHome base directory.
|
||||||
|
// This set of directories is defined by the $XDG_DATA_DIRS environment
|
||||||
|
// variable. If the variable is not set, the default directories
|
||||||
|
// to be used are /usr/local/share and /usr/share, in that order. The
|
||||||
|
// DataHome directory is considered more important than any of the
|
||||||
|
// directories defined by DataDirs. Therefore, user data files should be
|
||||||
|
// written relative to the DataHome directory, if possible.
|
||||||
|
DataDirs []string
|
||||||
|
|
||||||
|
// ConfigHome defines the base directory relative to which user-specific
|
||||||
|
// configuration files should be written. This directory is defined by
|
||||||
|
// the $XDG_CONFIG_HOME environment variable. If the variable is
|
||||||
|
// not set, a default equal to $HOME/.config should be used.
|
||||||
|
ConfigHome string
|
||||||
|
|
||||||
|
// ConfigDirs defines the preference-ordered set of base directories to
|
||||||
|
// search for configuration files in addition to the ConfigHome base
|
||||||
|
// directory. This set of directories is defined by the $XDG_CONFIG_DIRS
|
||||||
|
// environment variable. If the variable is not set, a default equal
|
||||||
|
// to /etc/xdg should be used. The ConfigHome directory is considered
|
||||||
|
// more important than any of the directories defined by ConfigDirs.
|
||||||
|
// Therefore, user config files should be written relative to the
|
||||||
|
// ConfigHome directory, if possible.
|
||||||
|
ConfigDirs []string
|
||||||
|
|
||||||
|
// StateHome defines the base directory relative to which user-specific
|
||||||
|
// state files should be stored. This directory is defined by the
|
||||||
|
// $XDG_STATE_HOME environment variable. If the variable is not set,
|
||||||
|
// a default equal to ~/.local/state should be used.
|
||||||
|
StateHome string
|
||||||
|
|
||||||
|
// CacheHome defines the base directory relative to which user-specific
|
||||||
|
// non-essential (cached) data should be written. This directory is
|
||||||
|
// defined by the $XDG_CACHE_HOME environment variable. If the variable
|
||||||
|
// is not set, a default equal to $HOME/.cache should be used.
|
||||||
|
CacheHome string
|
||||||
|
|
||||||
|
// RuntimeDir defines the base directory relative to which user-specific
|
||||||
|
// non-essential runtime files and other file objects (such as sockets,
|
||||||
|
// named pipes, etc.) should be stored. This directory is defined by the
|
||||||
|
// $XDG_RUNTIME_DIR environment variable. If the variable is not set,
|
||||||
|
// applications should fall back to a replacement directory with similar
|
||||||
|
// capabilities. Applications should use this directory for communication
|
||||||
|
// and synchronization purposes and should not place larger files in it,
|
||||||
|
// since it might reside in runtime memory and cannot necessarily be
|
||||||
|
// swapped out to disk.
|
||||||
|
RuntimeDir string
|
||||||
|
|
||||||
|
// BinHome defines the base directory relative to which user-specific
|
||||||
|
// binary files should be written. This directory is defined by
|
||||||
|
// the non-standard $XDG_BIN_HOME environment variable. If the variable is
|
||||||
|
// not set, a default equal to $HOME/.local/bin should be used.
|
||||||
|
BinHome string
|
||||||
|
|
||||||
|
// UserDirs defines the locations of well known user directories.
|
||||||
|
UserDirs UserDirectories
|
||||||
|
|
||||||
|
// FontDirs defines the common locations where font files are stored.
|
||||||
|
FontDirs []string
|
||||||
|
|
||||||
|
// ApplicationDirs defines the common locations of applications.
|
||||||
|
ApplicationDirs []string
|
||||||
|
|
||||||
|
// baseDirs defines the locations of base directories.
|
||||||
|
baseDirs baseDirectories
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload refreshes base and user directories by reading the environment.
|
||||||
|
// Defaults are applied for XDG variables which are empty or not present
|
||||||
|
// in the environment.
|
||||||
|
func Reload() {
|
||||||
|
// Initialize home directory.
|
||||||
|
Home = pathutil.UserHomeDir()
|
||||||
|
|
||||||
|
// Initialize base and user directories.
|
||||||
|
initDirs(Home)
|
||||||
|
|
||||||
|
// Set standard directories.
|
||||||
|
DataHome = baseDirs.dataHome
|
||||||
|
DataDirs = baseDirs.data
|
||||||
|
ConfigHome = baseDirs.configHome
|
||||||
|
ConfigDirs = baseDirs.config
|
||||||
|
StateHome = baseDirs.stateHome
|
||||||
|
CacheHome = baseDirs.cacheHome
|
||||||
|
RuntimeDir = baseDirs.runtime
|
||||||
|
|
||||||
|
// Set non-standard directories.
|
||||||
|
BinHome = baseDirs.binHome
|
||||||
|
FontDirs = baseDirs.fonts
|
||||||
|
ApplicationDirs = baseDirs.applications
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataFile returns a suitable location for the specified data file.
|
||||||
|
// The relPath parameter must contain the name of the data file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.data).
|
||||||
|
// If the specified directories do not exist, they will be created relative
|
||||||
|
// to the base data directory. On failure, an error containing the
|
||||||
|
// attempted paths is returned.
|
||||||
|
func DataFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.dataFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFile returns a suitable location for the specified config file.
|
||||||
|
// The relPath parameter must contain the name of the config file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.yaml).
|
||||||
|
// If the specified directories do not exist, they will be created relative
|
||||||
|
// to the base config directory. On failure, an error containing the
|
||||||
|
// attempted paths is returned.
|
||||||
|
func ConfigFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.configFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateFile returns a suitable location for the specified state file. State
|
||||||
|
// files are usually volatile data files, not suitable to be stored relative
|
||||||
|
// to the $XDG_DATA_HOME directory.
|
||||||
|
// The relPath parameter must contain the name of the state file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.state).
|
||||||
|
// If the specified directories do not exist, they will be created relative
|
||||||
|
// to the base state directory. On failure, an error containing the
|
||||||
|
// attempted paths is returned.
|
||||||
|
func StateFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.stateFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheFile returns a suitable location for the specified cache file.
|
||||||
|
// The relPath parameter must contain the name of the cache file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.cache).
|
||||||
|
// If the specified directories do not exist, they will be created relative
|
||||||
|
// to the base cache directory. On failure, an error containing the
|
||||||
|
// attempted paths is returned.
|
||||||
|
func CacheFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.cacheFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeFile returns a suitable location for the specified runtime file.
|
||||||
|
// The relPath parameter must contain the name of the runtime file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.pid).
|
||||||
|
// If the specified directories do not exist, they will be created relative
|
||||||
|
// to the base runtime directory. If the base runtime directory does not exist,
|
||||||
|
// the operating system's temporary directory is used as a fallback. On failure,
|
||||||
|
// an error containing the attempted paths is returned.
|
||||||
|
func RuntimeFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.runtimeFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchDataFile searches for specified file in the data search paths.
|
||||||
|
// The relPath parameter must contain the name of the data file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.data). If the
|
||||||
|
// file cannot be found, an error specifying the searched paths is returned.
|
||||||
|
func SearchDataFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.searchDataFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchConfigFile searches for the specified file in config search paths.
|
||||||
|
// The relPath parameter must contain the name of the config file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.yaml). If the
|
||||||
|
// file cannot be found, an error specifying the searched paths is returned.
|
||||||
|
func SearchConfigFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.searchConfigFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchStateFile searches for the specified file in the state search path.
|
||||||
|
// The relPath parameter must contain the name of the state file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.state). If the
|
||||||
|
// file cannot be found, an error specifying the searched path is returned.
|
||||||
|
func SearchStateFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.searchStateFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchCacheFile searches for the specified file in the cache search path.
|
||||||
|
// The relPath parameter must contain the name of the cache file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.cache). If the
|
||||||
|
// file cannot be found, an error specifying the searched path is returned.
|
||||||
|
func SearchCacheFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.searchCacheFile(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchRuntimeFile searches for the specified file in the runtime search path.
|
||||||
|
// The relPath parameter must contain the name of the runtime file, and
|
||||||
|
// optionally, a set of parent directories (e.g. appname/app.pid). The runtime
|
||||||
|
// file is also searched in the operating system's temporary directory in order
|
||||||
|
// to cover cases in which the runtime base directory does not exist or is not
|
||||||
|
// accessible. If the file cannot be found, an error specifying the searched
|
||||||
|
// paths is returned.
|
||||||
|
func SearchRuntimeFile(relPath string) (string, error) {
|
||||||
|
return baseDirs.searchRuntimeFile(relPath)
|
||||||
|
}
|
||||||
6
vendor/github.com/apapsch/go-jsonmerge/v2/.editorconfig
generated
vendored
Normal file
6
vendor/github.com/apapsch/go-jsonmerge/v2/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{cmd,bat}]
|
||||||
|
end_of_line = crlf
|
||||||
175
vendor/github.com/apapsch/go-jsonmerge/v2/.gitattributes
generated
vendored
Normal file
175
vendor/github.com/apapsch/go-jsonmerge/v2/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
## AUTO-DETECT - Handle line endings automatically for files detected
|
||||||
|
## as text and leave all files detected as binary untouched.
|
||||||
|
## This will handle all files NOT defined below.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Custom for Visual Studio
|
||||||
|
*.sln text eol=crlf
|
||||||
|
*.csproj text eol=crlf
|
||||||
|
*.vbproj text eol=crlf
|
||||||
|
*.fsproj text eol=crlf
|
||||||
|
*.dbproj text eol=crlf
|
||||||
|
|
||||||
|
*.vcxproj text eol=crlf
|
||||||
|
*.vcxitems text eol=crlf
|
||||||
|
*.props text eol=crlf
|
||||||
|
*.filters text eol=crlf
|
||||||
|
|
||||||
|
# Documents
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
||||||
|
*.csv text
|
||||||
|
*.sql text
|
||||||
|
*.ini text
|
||||||
|
|
||||||
|
## SOURCE CODE
|
||||||
|
*.go text eol=lf
|
||||||
|
*.c text eol=lf
|
||||||
|
*.h text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.coffee text eol=lf
|
||||||
|
|
||||||
|
*.htm text diff=html
|
||||||
|
*.html text diff=html
|
||||||
|
*.xml text diff=html
|
||||||
|
*.xhtml text diff=html
|
||||||
|
|
||||||
|
*.js text eol=lf
|
||||||
|
*.jsx text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.ts text eol=lf
|
||||||
|
|
||||||
|
*.css text diff=css eol=lf
|
||||||
|
*.scss text diff=css eol=lf
|
||||||
|
*.less text diff=css eol=lf
|
||||||
|
*.sass text eol=lf
|
||||||
|
|
||||||
|
*.sh text eol=lf
|
||||||
|
|
||||||
|
## DOCUMENTATION
|
||||||
|
*.md text eol=lf
|
||||||
|
*.txt text
|
||||||
|
AUTHORS text eol=lf
|
||||||
|
CHANGELOG text eol=lf
|
||||||
|
CHANGES text eol=lf
|
||||||
|
CONTRIBUTING text eol=lf
|
||||||
|
COPYING text eol=lf
|
||||||
|
INSTALL text eol=lf
|
||||||
|
license text eol=lf
|
||||||
|
LICENSE text eol=lf
|
||||||
|
NEWS text eol=lf
|
||||||
|
readme text eol=lf
|
||||||
|
*README* text eol=lf
|
||||||
|
TODO text eol=lf
|
||||||
|
|
||||||
|
## TEMPLATES
|
||||||
|
*.dot text
|
||||||
|
*.ejs text
|
||||||
|
*.haml text
|
||||||
|
*.handlebars text
|
||||||
|
*.hbs text
|
||||||
|
*.hbt text
|
||||||
|
*.jade text
|
||||||
|
*.latte text
|
||||||
|
*.mustache text
|
||||||
|
*.tmpl text
|
||||||
|
|
||||||
|
## LINTERS
|
||||||
|
.csslintrc text eol=lf
|
||||||
|
.eslintrc text eol=lf
|
||||||
|
.jscsrc text eol=lf
|
||||||
|
.jshintrc text eol=lf
|
||||||
|
.jshintignore text eol=lf
|
||||||
|
.stylelintrc text eol=lf
|
||||||
|
|
||||||
|
## CONFIGS
|
||||||
|
*.bowerrc text eol=lf
|
||||||
|
*.cnf text
|
||||||
|
*.conf text
|
||||||
|
*.config text
|
||||||
|
.editorconfig text eol=lf
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
.gitconfig text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
|
*.npmignore text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
Makefile text eol=lf
|
||||||
|
makefile text eol=lf
|
||||||
|
|
||||||
|
## GRAPHICS
|
||||||
|
*.ai binary
|
||||||
|
*.bmp binary
|
||||||
|
*.eps binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.jng binary
|
||||||
|
*.jp2 binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.jpx binary
|
||||||
|
*.jxr binary
|
||||||
|
*.pdf binary
|
||||||
|
*.png binary
|
||||||
|
*.psb binary
|
||||||
|
*.psd binary
|
||||||
|
*.svg text
|
||||||
|
*.svgz binary
|
||||||
|
*.tif binary
|
||||||
|
*.tiff binary
|
||||||
|
*.wbmp binary
|
||||||
|
*.webp binary
|
||||||
|
|
||||||
|
## AUDIO
|
||||||
|
*.kar binary
|
||||||
|
*.m4a binary
|
||||||
|
*.mid binary
|
||||||
|
*.midi binary
|
||||||
|
*.mp3 binary
|
||||||
|
*.ogg binary
|
||||||
|
*.ra binary
|
||||||
|
|
||||||
|
## VIDEO
|
||||||
|
*.3gpp binary
|
||||||
|
*.3gp binary
|
||||||
|
*.as binary
|
||||||
|
*.asf binary
|
||||||
|
*.asx binary
|
||||||
|
*.fla binary
|
||||||
|
*.flv binary
|
||||||
|
*.m4v binary
|
||||||
|
*.mng binary
|
||||||
|
*.mov binary
|
||||||
|
*.mp4 binary
|
||||||
|
*.mpeg binary
|
||||||
|
*.mpg binary
|
||||||
|
*.swc binary
|
||||||
|
*.swf binary
|
||||||
|
*.webm binary
|
||||||
|
|
||||||
|
## ARCHIVES
|
||||||
|
*.7z binary
|
||||||
|
*.gz binary
|
||||||
|
*.rar binary
|
||||||
|
*.tar binary
|
||||||
|
*.zip binary
|
||||||
|
|
||||||
|
## FONTS
|
||||||
|
*.ttf binary
|
||||||
|
*.eot binary
|
||||||
|
*.otf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
|
||||||
|
## EXECUTABLES
|
||||||
|
*.exe binary
|
||||||
|
*.dll binary
|
||||||
11
vendor/github.com/apapsch/go-jsonmerge/v2/.gitignore
generated
vendored
Normal file
11
vendor/github.com/apapsch/go-jsonmerge/v2/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# GoLand
|
||||||
|
/.idea/
|
||||||
|
|
||||||
|
/vendor/
|
||||||
|
|
||||||
|
/cmd/cmd.exe
|
||||||
|
/cmd/cmd
|
||||||
|
|
||||||
|
/artifacts/
|
||||||
|
/test/
|
||||||
|
/cmd/test/
|
||||||
42
vendor/github.com/apapsch/go-jsonmerge/v2/.gitlab-ci.yml
generated
vendored
Normal file
42
vendor/github.com/apapsch/go-jsonmerge/v2/.gitlab-ci.yml
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
variables:
|
||||||
|
GOPROJ: "github.com/RaveNoX/go-jsonmerge"
|
||||||
|
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- test
|
||||||
|
- build
|
||||||
|
|
||||||
|
test:
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
- linux
|
||||||
|
image: golang:latest
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- mkdir -p artifacts
|
||||||
|
- go test -cover -v -coverprofile="./artifacts/cover.out" ./
|
||||||
|
- go tool cover -html="./artifacts/cover.out" -o "./artifacts/cover.htm"
|
||||||
|
- go test -cover -v -coverprofile="./artifacts/cover_cmd.out" ./cmd/jsonmerge
|
||||||
|
- go tool cover -html="./artifacts/cover_cmd.out" -o "./artifacts/cover_cmd.htm"
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- artifacts/*
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
- linux
|
||||||
|
image: golang:latest
|
||||||
|
script:
|
||||||
|
- mkdir -p artifacts
|
||||||
|
- echo "Building for Linux"
|
||||||
|
- GOOS=linux GOARCH=amd64 go build -o artifacts/jsonmerge ./cmd/jsonmerge
|
||||||
|
- echo "Building for MacOS (darwin)"
|
||||||
|
- GOOS=darwin GOARCH=amd64 go build -o artifacts/jsonmerge_darwin ./cmd/jsonmerge
|
||||||
|
- echo "Building for Windows"
|
||||||
|
- GOOS=windows GOARCH=amd64 go build -o artifacts/jsonmerge.exe ./cmd/jsonmerge
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- artifacts/*
|
||||||
|
|
||||||
19
vendor/github.com/apapsch/go-jsonmerge/v2/.travis.yml
generated
vendored
Normal file
19
vendor/github.com/apapsch/go-jsonmerge/v2/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
|
||||||
|
install:
|
||||||
|
- mkdir -p artifacts
|
||||||
|
|
||||||
|
env:
|
||||||
|
- GO111MODULE=on
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -cover -v -coverprofile="./artifacts/cover.out" ./
|
||||||
|
- go tool cover -html="./artifacts/cover.out" -o "./artifacts/cover.htm"
|
||||||
|
- go test -cover -v -coverprofile="./artifacts/cover_cmd.out" ./cmd/jsonmerge
|
||||||
|
- go tool cover -html="./artifacts/cover_cmd.out" -o "./artifacts/cover_cmd.htm"
|
||||||
|
- GOARCH=amd64 GOOS=linux go build -o artifacts/jsonmerge ./cmd/jsonmerge
|
||||||
|
- GOARCH=amd64 GOOS=windows go build -o artifacts/jsonmerge.exe ./cmd/jsonmerge
|
||||||
|
- GOARCH=amd64 GOOS=darwin go build -o artifacts/jsonmerge_darwin ./cmd/jsonmerge
|
||||||
21
vendor/github.com/apapsch/go-jsonmerge/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/apapsch/go-jsonmerge/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016-2019 Artur Kraev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
81
vendor/github.com/apapsch/go-jsonmerge/v2/README.md
generated
vendored
Normal file
81
vendor/github.com/apapsch/go-jsonmerge/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# go-jsonmerge
|
||||||
|
[](https://travis-ci.org/RaveNoX/go-jsonmerge)
|
||||||
|
[](https://godoc.org/github.com/RaveNoX/go-jsonmerge)
|
||||||
|
|
||||||
|
GO library for merging JSON objects
|
||||||
|
|
||||||
|
## Original document
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"number": 1,
|
||||||
|
"string": "value",
|
||||||
|
"object": {
|
||||||
|
"number": 1,
|
||||||
|
"string": "value",
|
||||||
|
"nested object": {
|
||||||
|
"number": 2
|
||||||
|
},
|
||||||
|
"array": [1, 2, 3],
|
||||||
|
"partial_array": [1, 2, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Patch
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"number": 2,
|
||||||
|
"string": "value1",
|
||||||
|
"nonexitent": "woot",
|
||||||
|
"object": {
|
||||||
|
"number": 3,
|
||||||
|
"string": "value2",
|
||||||
|
"nested object": {
|
||||||
|
"number": 4
|
||||||
|
},
|
||||||
|
"array": [3, 2, 1],
|
||||||
|
"partial_array": {
|
||||||
|
"1": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Result
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"number": 2,
|
||||||
|
"string": "value1",
|
||||||
|
"object": {
|
||||||
|
"number": 3,
|
||||||
|
"string": "value2",
|
||||||
|
"nested object": {
|
||||||
|
"number": 4
|
||||||
|
},
|
||||||
|
"array": [3, 2, 1],
|
||||||
|
"partial_array": [1, 4, 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commandline Tool
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ go get -u github.com/RaveNoX/go-jsonmerge/cmd/jsonmerge
|
||||||
|
$ jsonmerge [options] <patch.json> <glob1.json> <glob2.json>...<globN.json>
|
||||||
|
# For help
|
||||||
|
$ jsonmerge -h
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
```
|
||||||
|
# Install depencencies
|
||||||
|
./init.sh
|
||||||
|
|
||||||
|
# Build
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
[MIT](./LICENSE.MD)
|
||||||
25
vendor/github.com/apapsch/go-jsonmerge/v2/build.cmd
generated
vendored
Normal file
25
vendor/github.com/apapsch/go-jsonmerge/v2/build.cmd
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
set GOARCH=amd64
|
||||||
|
|
||||||
|
cd %~dp0
|
||||||
|
md artifacts
|
||||||
|
|
||||||
|
echo Windows
|
||||||
|
set GOOS=windows
|
||||||
|
call go build -o artifacts\jsonmerge.exe .\cmd || goto :error
|
||||||
|
|
||||||
|
echo Linux
|
||||||
|
set GOOS=linux
|
||||||
|
call go build -o artifacts\jsonmerge .\cmd || goto :error
|
||||||
|
|
||||||
|
echo Darwin
|
||||||
|
set GOOS=darwin
|
||||||
|
call go build -o artifacts\jsonmerge_darwin .\cmd || goto :error
|
||||||
|
|
||||||
|
echo Build done
|
||||||
|
exit
|
||||||
|
|
||||||
|
:error
|
||||||
|
exit /b %errorlevel%
|
||||||
19
vendor/github.com/apapsch/go-jsonmerge/v2/build.sh
generated
vendored
Normal file
19
vendor/github.com/apapsch/go-jsonmerge/v2/build.sh
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
MY_DIR=$(dirname "$0")
|
||||||
|
|
||||||
|
cd "${MY_DIR}"
|
||||||
|
mkdir -p "artifacts"
|
||||||
|
|
||||||
|
echo "Linux"
|
||||||
|
GOARCH=amd64 GOOS=linux go build -o "artifacts/jsonmerge" ./cmd
|
||||||
|
|
||||||
|
echo "Windows"
|
||||||
|
GOARCH=amd64 GOOS=windows go build -o "artifacts/jsonmerge.exe" ./cmd
|
||||||
|
|
||||||
|
echo "Mac(darwin)"
|
||||||
|
GOARCH=amd64 GOOS=darwin go build -o "artifacts/jsonmerge_darwin" ./cmd
|
||||||
|
|
||||||
|
echo "Build done"
|
||||||
52
vendor/github.com/apapsch/go-jsonmerge/v2/doc.go
generated
vendored
Normal file
52
vendor/github.com/apapsch/go-jsonmerge/v2/doc.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Package jsonmerge helps mergeing JSON objects
|
||||||
|
//
|
||||||
|
// For example you have this documents:
|
||||||
|
//
|
||||||
|
// original.json
|
||||||
|
// {
|
||||||
|
// "number": 1,
|
||||||
|
// "string": "value",
|
||||||
|
// "object": {
|
||||||
|
// "number": 1,
|
||||||
|
// "string": "value",
|
||||||
|
// "nested object": {
|
||||||
|
// "number": 2
|
||||||
|
// },
|
||||||
|
// "array": [1, 2, 3],
|
||||||
|
// "partial_array": [1, 2, 3]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// patch.json
|
||||||
|
// {
|
||||||
|
// "number": 2,
|
||||||
|
// "string": "value1",
|
||||||
|
// "nonexitent": "woot",
|
||||||
|
// "object": {
|
||||||
|
// "number": 3,
|
||||||
|
// "string": "value2",
|
||||||
|
// "nested object": {
|
||||||
|
// "number": 4
|
||||||
|
// },
|
||||||
|
// "array": [3, 2, 1],
|
||||||
|
// "partial_array": {
|
||||||
|
// "1": 4
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// After merge you will have this result:
|
||||||
|
// {
|
||||||
|
// "number": 2,
|
||||||
|
// "string": "value1",
|
||||||
|
// "object": {
|
||||||
|
// "number": 3,
|
||||||
|
// "string": "value2",
|
||||||
|
// "nested object": {
|
||||||
|
// "number": 4
|
||||||
|
// },
|
||||||
|
// "array": [3, 2, 1],
|
||||||
|
// "partial_array": [1, 4, 3]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
package jsonmerge
|
||||||
167
vendor/github.com/apapsch/go-jsonmerge/v2/merge.go
generated
vendored
Normal file
167
vendor/github.com/apapsch/go-jsonmerge/v2/merge.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package jsonmerge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Merger describes result of merge operation and provides
|
||||||
|
// configuration.
|
||||||
|
type Merger struct {
|
||||||
|
// Errors is slice of non-critical errors of merge operations
|
||||||
|
Errors []error
|
||||||
|
// Replaced is describe replacements
|
||||||
|
// Key is path in document like
|
||||||
|
// "prop1.prop2.prop3" for object properties or
|
||||||
|
// "arr1.1.prop" for arrays
|
||||||
|
// Value is value of replacemet
|
||||||
|
Replaced map[string]interface{}
|
||||||
|
// CopyNonexistent enables setting fields into the result
|
||||||
|
// which only exist in the patch.
|
||||||
|
CopyNonexistent bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Merger) mergeValue(path []string, patch map[string]interface{}, key string, value interface{}) interface{} {
|
||||||
|
patchValue, patchHasValue := patch[key]
|
||||||
|
|
||||||
|
if !patchHasValue {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
_, patchValueIsObject := patchValue.(map[string]interface{})
|
||||||
|
|
||||||
|
path = append(path, key)
|
||||||
|
pathStr := strings.Join(path, ".")
|
||||||
|
|
||||||
|
if _, ok := value.(map[string]interface{}); ok {
|
||||||
|
if !patchValueIsObject {
|
||||||
|
err := fmt.Errorf("patch value must be object for key \"%v\"", pathStr)
|
||||||
|
m.Errors = append(m.Errors, err)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.mergeObjects(value, patchValue, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := value.([]interface{}); ok && patchValueIsObject {
|
||||||
|
return m.mergeObjects(value, patchValue, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(value, patchValue) {
|
||||||
|
m.Replaced[pathStr] = patchValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return patchValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Merger) mergeObjects(data, patch interface{}, path []string) interface{} {
|
||||||
|
if patchObject, ok := patch.(map[string]interface{}); ok {
|
||||||
|
if dataArray, ok := data.([]interface{}); ok {
|
||||||
|
ret := make([]interface{}, len(dataArray))
|
||||||
|
|
||||||
|
for i, val := range dataArray {
|
||||||
|
ret[i] = m.mergeValue(path, patchObject, strconv.Itoa(i), val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
} else if dataObject, ok := data.(map[string]interface{}); ok {
|
||||||
|
ret := make(map[string]interface{})
|
||||||
|
|
||||||
|
for k, v := range dataObject {
|
||||||
|
ret[k] = m.mergeValue(path, patchObject, k, v)
|
||||||
|
}
|
||||||
|
if m.CopyNonexistent {
|
||||||
|
for k, v := range patchObject {
|
||||||
|
if _, ok := dataObject[k]; !ok {
|
||||||
|
ret[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges patch document to data document
|
||||||
|
//
|
||||||
|
// Returning merged document. Result of merge operation can be
|
||||||
|
// obtained from the Merger. Result information is discarded before
|
||||||
|
// merging.
|
||||||
|
func (m *Merger) Merge(data, patch interface{}) interface{} {
|
||||||
|
m.Replaced = make(map[string]interface{})
|
||||||
|
m.Errors = make([]error, 0)
|
||||||
|
return m.mergeObjects(data, patch, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBytesIndent merges patch document buffer to data document buffer
|
||||||
|
//
|
||||||
|
// Use prefix and indent for set indentation like in json.MarshalIndent
|
||||||
|
//
|
||||||
|
// Returning merged document buffer and error if any.
|
||||||
|
func (m *Merger) MergeBytesIndent(dataBuff, patchBuff []byte, prefix, indent string) (mergedBuff []byte, err error) {
|
||||||
|
var data, patch, merged interface{}
|
||||||
|
|
||||||
|
err = unmarshalJSON(dataBuff, &data)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error in data JSON: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unmarshalJSON(patchBuff, &patch)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error in patch JSON: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
merged = m.Merge(data, patch)
|
||||||
|
|
||||||
|
mergedBuff, err = json.MarshalIndent(merged, prefix, indent)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error writing merged JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeBytes merges patch document buffer to data document buffer
|
||||||
|
//
|
||||||
|
// Returning merged document buffer, merge info and
|
||||||
|
// error if any
|
||||||
|
func (m *Merger) MergeBytes(dataBuff, patchBuff []byte) (mergedBuff []byte, err error) {
|
||||||
|
var data, patch, merged interface{}
|
||||||
|
|
||||||
|
err = unmarshalJSON(dataBuff, &data)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error in data JSON: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unmarshalJSON(patchBuff, &patch)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error in patch JSON: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
merged = m.Merge(data, patch)
|
||||||
|
|
||||||
|
mergedBuff, err = json.Marshal(merged)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error writing merged JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalJSON(buff []byte, data interface{}) error {
|
||||||
|
decoder := json.NewDecoder(bytes.NewReader(buff))
|
||||||
|
decoder.UseNumber()
|
||||||
|
|
||||||
|
return decoder.Decode(data)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user