googleauth 0.5.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +7 -0
- data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +5 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- data/.github/ISSUE_TEMPLATE/support_request.md +7 -0
- data/.kokoro/build.bat +16 -0
- data/.kokoro/build.sh +4 -0
- data/.kokoro/continuous/common.cfg +24 -0
- data/.kokoro/continuous/linux.cfg +25 -0
- data/.kokoro/continuous/osx.cfg +8 -0
- data/.kokoro/continuous/post.cfg +30 -0
- data/.kokoro/continuous/windows.cfg +29 -0
- data/.kokoro/osx.sh +4 -0
- data/.kokoro/presubmit/common.cfg +24 -0
- data/.kokoro/presubmit/linux.cfg +24 -0
- data/.kokoro/presubmit/osx.cfg +8 -0
- data/.kokoro/presubmit/windows.cfg +29 -0
- data/.kokoro/release.cfg +94 -0
- data/.kokoro/trampoline.bat +10 -0
- data/.kokoro/trampoline.sh +4 -0
- data/.repo-metadata.json +5 -0
- data/.rubocop.yml +19 -1
- data/CHANGELOG.md +112 -19
- data/CODE_OF_CONDUCT.md +43 -0
- data/Gemfile +19 -13
- data/{COPYING → LICENSE} +0 -0
- data/README.md +58 -18
- data/Rakefile +126 -9
- data/googleauth.gemspec +28 -25
- data/integration/helper.rb +31 -0
- data/integration/id_tokens/key_source_test.rb +74 -0
- data/lib/googleauth.rb +7 -96
- data/lib/googleauth/application_default.rb +81 -0
- data/lib/googleauth/client_id.rb +21 -19
- data/lib/googleauth/compute_engine.rb +70 -43
- data/lib/googleauth/credentials.rb +442 -0
- data/lib/googleauth/credentials_loader.rb +117 -43
- data/lib/googleauth/default_credentials.rb +93 -0
- data/lib/googleauth/iam.rb +11 -11
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/id_tokens/errors.rb +71 -0
- data/lib/googleauth/id_tokens/key_sources.rb +394 -0
- data/lib/googleauth/id_tokens/verifier.rb +144 -0
- data/lib/googleauth/json_key_reader.rb +50 -0
- data/lib/googleauth/scope_util.rb +12 -12
- data/lib/googleauth/service_account.rb +74 -63
- data/lib/googleauth/signet.rb +55 -13
- data/lib/googleauth/stores/file_token_store.rb +8 -8
- data/lib/googleauth/stores/redis_token_store.rb +22 -22
- data/lib/googleauth/token_store.rb +6 -6
- data/lib/googleauth/user_authorizer.rb +80 -68
- data/lib/googleauth/user_refresh.rb +44 -35
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +77 -68
- data/rakelib/devsite_builder.rb +45 -0
- data/rakelib/link_checker.rb +64 -0
- data/rakelib/repo_metadata.rb +59 -0
- data/spec/googleauth/apply_auth_examples.rb +74 -50
- data/spec/googleauth/client_id_spec.rb +75 -55
- data/spec/googleauth/compute_engine_spec.rb +98 -46
- data/spec/googleauth/credentials_spec.rb +478 -0
- data/spec/googleauth/get_application_default_spec.rb +149 -111
- data/spec/googleauth/iam_spec.rb +25 -25
- data/spec/googleauth/scope_util_spec.rb +26 -24
- data/spec/googleauth/service_account_spec.rb +269 -144
- data/spec/googleauth/signet_spec.rb +101 -30
- data/spec/googleauth/stores/file_token_store_spec.rb +12 -13
- data/spec/googleauth/stores/redis_token_store_spec.rb +11 -11
- data/spec/googleauth/stores/store_examples.rb +16 -16
- data/spec/googleauth/user_authorizer_spec.rb +153 -124
- data/spec/googleauth/user_refresh_spec.rb +186 -121
- data/spec/googleauth/web_user_authorizer_spec.rb +82 -69
- data/spec/spec_helper.rb +21 -19
- data/test/helper.rb +33 -0
- data/test/id_tokens/key_sources_test.rb +240 -0
- data/test/id_tokens/verifier_test.rb +269 -0
- metadata +87 -34
- data/.rubocop_todo.yml +0 -32
- data/.travis.yml +0 -37
data/googleauth.gemspec
CHANGED
@@ -1,35 +1,38 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
# encoding: utf-8
|
3
|
-
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
4
|
-
require 'googleauth/version'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
$LOAD_PATH.push File.expand_path("lib", __dir__)
|
5
|
+
require "googleauth/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.name = "googleauth"
|
9
|
+
gem.version = Google::Auth::VERSION
|
10
|
+
gem.authors = ["Tim Emiola"]
|
11
|
+
gem.email = "temiola@google.com"
|
12
|
+
gem.homepage = "https://github.com/googleapis/google-auth-library-ruby"
|
13
|
+
gem.summary = "Google Auth Library for Ruby"
|
14
|
+
gem.license = "Apache-2.0"
|
15
|
+
gem.description = <<-DESCRIPTION
|
15
16
|
Allows simple authorization for accessing Google APIs.
|
16
17
|
Provide support for Application Default Credentials, as described at
|
17
18
|
https://developers.google.com/accounts/docs/application-default-credentials
|
18
|
-
|
19
|
+
DESCRIPTION
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
File.basename
|
21
|
+
gem.files = `git ls-files`.split "\n"
|
22
|
+
gem.test_files = `git ls-files -- spec/*`.split "\n"
|
23
|
+
gem.executables = `git ls-files -- bin/*.rb`.split("\n").map do |f|
|
24
|
+
File.basename f
|
24
25
|
end
|
25
|
-
|
26
|
-
|
26
|
+
gem.require_paths = ["lib"]
|
27
|
+
gem.platform = Gem::Platform::RUBY
|
28
|
+
gem.required_ruby_version = ">= 2.4.0"
|
29
|
+
|
30
|
+
gem.add_dependency "faraday", ">= 0.17.3", "< 2.0"
|
31
|
+
gem.add_dependency "jwt", ">= 1.4", "< 3.0"
|
32
|
+
gem.add_dependency "memoist", "~> 0.16"
|
33
|
+
gem.add_dependency "multi_json", "~> 1.11"
|
34
|
+
gem.add_dependency "os", ">= 0.9", "< 2.0"
|
35
|
+
gem.add_dependency "signet", "~> 0.14"
|
27
36
|
|
28
|
-
|
29
|
-
s.add_dependency 'logging', '~> 2.0'
|
30
|
-
s.add_dependency 'jwt', '~> 1.4'
|
31
|
-
s.add_dependency 'memoist', '~> 0.12'
|
32
|
-
s.add_dependency 'multi_json', '~> 1.11'
|
33
|
-
s.add_dependency 'os', '~> 0.9'
|
34
|
-
s.add_dependency 'signet', '~> 0.7'
|
37
|
+
gem.add_development_dependency "yard", "~> 0.9"
|
35
38
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright 2020 Google LLC
|
2
|
+
#
|
3
|
+
# Redistribution and use in source and binary forms, with or without
|
4
|
+
# modification, are permitted provided that the following conditions are
|
5
|
+
# met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following disclaimer
|
11
|
+
# in the documentation and/or other materials provided with the
|
12
|
+
# distribution.
|
13
|
+
# * Neither the name of Google Inc. nor the names of its
|
14
|
+
# contributors may be used to endorse or promote products derived from
|
15
|
+
# this software without specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
18
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
19
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
20
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
21
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
|
29
|
+
require "minitest/autorun"
|
30
|
+
require "minitest/focus"
|
31
|
+
require "googleauth"
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Copyright 2020 Google LLC
|
2
|
+
#
|
3
|
+
# Redistribution and use in source and binary forms, with or without
|
4
|
+
# modification, are permitted provided that the following conditions are
|
5
|
+
# met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following disclaimer
|
11
|
+
# in the documentation and/or other materials provided with the
|
12
|
+
# distribution.
|
13
|
+
# * Neither the name of Google Inc. nor the names of its
|
14
|
+
# contributors may be used to endorse or promote products derived from
|
15
|
+
# this software without specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
18
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
19
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
20
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
21
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
|
29
|
+
require "helper"
|
30
|
+
|
31
|
+
describe Google::Auth::IDTokens do
|
32
|
+
describe "key source" do
|
33
|
+
let(:legacy_oidc_key_source) {
|
34
|
+
Google::Auth::IDTokens::X509CertHttpKeySource.new "https://www.googleapis.com/oauth2/v1/certs"
|
35
|
+
}
|
36
|
+
let(:oidc_key_source) { Google::Auth::IDTokens.oidc_key_source }
|
37
|
+
let(:iap_key_source) { Google::Auth::IDTokens.iap_key_source }
|
38
|
+
|
39
|
+
it "Gets real keys from the OAuth2 V1 cert URL" do
|
40
|
+
keys = legacy_oidc_key_source.refresh_keys
|
41
|
+
refute_empty keys
|
42
|
+
keys.each do |key|
|
43
|
+
assert_kind_of OpenSSL::PKey::RSA, key.key
|
44
|
+
refute key.key.private?
|
45
|
+
assert_equal "RS256", key.algorithm
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "Gets real keys from the OAuth2 V3 cert URL" do
|
50
|
+
keys = oidc_key_source.refresh_keys
|
51
|
+
refute_empty keys
|
52
|
+
keys.each do |key|
|
53
|
+
assert_kind_of OpenSSL::PKey::RSA, key.key
|
54
|
+
refute key.key.private?
|
55
|
+
assert_equal "RS256", key.algorithm
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "Gets the same keys from the OAuth2 V1 and V3 cert URLs" do
|
60
|
+
keys_v1 = legacy_oidc_key_source.refresh_keys.map(&:key).map(&:export).sort
|
61
|
+
keys_v3 = oidc_key_source.refresh_keys.map(&:key).map(&:export).sort
|
62
|
+
assert_equal keys_v1, keys_v3
|
63
|
+
end
|
64
|
+
|
65
|
+
it "Gets real keys from the IAP public key URL" do
|
66
|
+
keys = iap_key_source.refresh_keys
|
67
|
+
refute_empty keys
|
68
|
+
keys.each do |key|
|
69
|
+
assert_kind_of OpenSSL::PKey::EC, key.key
|
70
|
+
assert_equal "ES256", key.algorithm
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/googleauth.rb
CHANGED
@@ -27,99 +27,10 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
31
|
-
require
|
32
|
-
|
33
|
-
require
|
34
|
-
require
|
35
|
-
require
|
36
|
-
require
|
37
|
-
require 'googleauth/client_id'
|
38
|
-
require 'googleauth/user_authorizer'
|
39
|
-
require 'googleauth/web_user_authorizer'
|
40
|
-
|
41
|
-
module Google
|
42
|
-
# Module Auth provides classes that provide Google-specific authorization
|
43
|
-
# used to access Google APIs.
|
44
|
-
module Auth
|
45
|
-
NOT_FOUND_ERROR = <<END
|
46
|
-
Could not load the default credentials. Browse to
|
47
|
-
https://developers.google.com/accounts/docs/application-default-credentials
|
48
|
-
for more information
|
49
|
-
END
|
50
|
-
|
51
|
-
# DefaultCredentials is used to preload the credentials file, to determine
|
52
|
-
# which type of credentials should be loaded.
|
53
|
-
class DefaultCredentials
|
54
|
-
extend CredentialsLoader
|
55
|
-
|
56
|
-
# override CredentialsLoader#make_creds to use the class determined by
|
57
|
-
# loading the json.
|
58
|
-
def self.make_creds(options = {})
|
59
|
-
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
60
|
-
if json_key_io
|
61
|
-
json_key, clz = determine_creds_class(json_key_io)
|
62
|
-
clz.make_creds(json_key_io: StringIO.new(MultiJson.dump(json_key)),
|
63
|
-
scope: scope)
|
64
|
-
else
|
65
|
-
clz = read_creds
|
66
|
-
clz.make_creds(scope: scope)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.read_creds
|
71
|
-
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
72
|
-
type = ENV[env_var]
|
73
|
-
fail "#{ACCOUNT_TYPE_VAR} is undefined in env" unless type
|
74
|
-
case type
|
75
|
-
when 'service_account'
|
76
|
-
ServiceAccountCredentials
|
77
|
-
when 'authorized_user'
|
78
|
-
UserRefreshCredentials
|
79
|
-
else
|
80
|
-
fail "credentials type '#{type}' is not supported"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Reads the input json and determines which creds class to use.
|
85
|
-
def self.determine_creds_class(json_key_io)
|
86
|
-
json_key = MultiJson.load(json_key_io.read)
|
87
|
-
key = 'type'
|
88
|
-
fail "the json is missing the '#{key}' field" unless json_key.key?(key)
|
89
|
-
type = json_key[key]
|
90
|
-
case type
|
91
|
-
when 'service_account'
|
92
|
-
[json_key, ServiceAccountCredentials]
|
93
|
-
when 'authorized_user'
|
94
|
-
[json_key, UserRefreshCredentials]
|
95
|
-
else
|
96
|
-
fail "credentials type '#{type}' is not supported"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Obtains the default credentials implementation to use in this
|
102
|
-
# environment.
|
103
|
-
#
|
104
|
-
# Use this to obtain the Application Default Credentials for accessing
|
105
|
-
# Google APIs. Application Default Credentials are described in detail
|
106
|
-
# at http://goo.gl/IUuyuX.
|
107
|
-
#
|
108
|
-
# If supplied, scope is used to create the credentials instance, when it can
|
109
|
-
# be applied. E.g, on google compute engine and for user credentials the
|
110
|
-
# scope is ignored.
|
111
|
-
#
|
112
|
-
# @param scope [string|array|nil] the scope(s) to access
|
113
|
-
# @param options [hash] allows override of the connection being used
|
114
|
-
def get_application_default(scope = nil, options = {})
|
115
|
-
creds = DefaultCredentials.from_env(scope) ||
|
116
|
-
DefaultCredentials.from_well_known_path(scope) ||
|
117
|
-
DefaultCredentials.from_system_default_path(scope)
|
118
|
-
return creds unless creds.nil?
|
119
|
-
fail NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
120
|
-
GCECredentials.new
|
121
|
-
end
|
122
|
-
|
123
|
-
module_function :get_application_default
|
124
|
-
end
|
125
|
-
end
|
30
|
+
require "googleauth/application_default"
|
31
|
+
require "googleauth/client_id"
|
32
|
+
require "googleauth/credentials"
|
33
|
+
require "googleauth/default_credentials"
|
34
|
+
require "googleauth/id_tokens"
|
35
|
+
require "googleauth/user_authorizer"
|
36
|
+
require "googleauth/web_user_authorizer"
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright 2015, Google Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are
|
6
|
+
# met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above
|
11
|
+
# copyright notice, this list of conditions and the following disclaimer
|
12
|
+
# in the documentation and/or other materials provided with the
|
13
|
+
# distribution.
|
14
|
+
# * Neither the name of Google Inc. nor the names of its
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
16
|
+
# this software without specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
require "googleauth/compute_engine"
|
31
|
+
require "googleauth/default_credentials"
|
32
|
+
|
33
|
+
module Google
|
34
|
+
# Module Auth provides classes that provide Google-specific authorization
|
35
|
+
# used to access Google APIs.
|
36
|
+
module Auth
|
37
|
+
NOT_FOUND_ERROR = <<~ERROR_MESSAGE.freeze
|
38
|
+
Could not load the default credentials. Browse to
|
39
|
+
https://developers.google.com/accounts/docs/application-default-credentials
|
40
|
+
for more information
|
41
|
+
ERROR_MESSAGE
|
42
|
+
|
43
|
+
module_function
|
44
|
+
|
45
|
+
# Obtains the default credentials implementation to use in this
|
46
|
+
# environment.
|
47
|
+
#
|
48
|
+
# Use this to obtain the Application Default Credentials for accessing
|
49
|
+
# Google APIs. Application Default Credentials are described in detail
|
50
|
+
# at https://cloud.google.com/docs/authentication/production.
|
51
|
+
#
|
52
|
+
# If supplied, scope is used to create the credentials instance, when it can
|
53
|
+
# be applied. E.g, on google compute engine and for user credentials the
|
54
|
+
# scope is ignored.
|
55
|
+
#
|
56
|
+
# @param scope [string|array|nil] the scope(s) to access
|
57
|
+
# @param options [Hash] Connection options. These may be used to configure
|
58
|
+
# the `Faraday::Connection` used for outgoing HTTP requests. For
|
59
|
+
# example, if a connection proxy must be used in the current network,
|
60
|
+
# you may provide a connection with with the needed proxy options.
|
61
|
+
# The following keys are recognized:
|
62
|
+
# * `:default_connection` The connection object to use for token
|
63
|
+
# refresh requests.
|
64
|
+
# * `:connection_builder` A `Proc` that creates and returns a
|
65
|
+
# connection to use for token refresh requests.
|
66
|
+
# * `:connection` The connection to use to determine whether GCE
|
67
|
+
# metadata credentials are available.
|
68
|
+
def get_application_default scope = nil, options = {}
|
69
|
+
creds = DefaultCredentials.from_env(scope, options) ||
|
70
|
+
DefaultCredentials.from_well_known_path(scope, options) ||
|
71
|
+
DefaultCredentials.from_system_default_path(scope, options)
|
72
|
+
return creds unless creds.nil?
|
73
|
+
unless GCECredentials.on_gce? options
|
74
|
+
# Clear cache of the result of GCECredentials.on_gce?
|
75
|
+
GCECredentials.unmemoize_all
|
76
|
+
raise NOT_FOUND_ERROR
|
77
|
+
end
|
78
|
+
GCECredentials.new scope: scope
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/googleauth/client_id.rb
CHANGED
@@ -27,19 +27,20 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
30
|
+
require "multi_json"
|
31
|
+
require "googleauth/credentials_loader"
|
31
32
|
|
32
33
|
module Google
|
33
34
|
module Auth
|
34
35
|
# Representation of an application's identity for user authorization
|
35
36
|
# flows.
|
36
37
|
class ClientId
|
37
|
-
INSTALLED_APP =
|
38
|
-
WEB_APP =
|
39
|
-
CLIENT_ID =
|
40
|
-
CLIENT_SECRET =
|
38
|
+
INSTALLED_APP = "installed".freeze
|
39
|
+
WEB_APP = "web".freeze
|
40
|
+
CLIENT_ID = "client_id".freeze
|
41
|
+
CLIENT_SECRET = "client_secret".freeze
|
41
42
|
MISSING_TOP_LEVEL_ELEMENT_ERROR =
|
42
|
-
"Expected top level property 'installed' or 'web' to be present."
|
43
|
+
"Expected top level property 'installed' or 'web' to be present.".freeze
|
43
44
|
|
44
45
|
# Text identifier of the client ID
|
45
46
|
# @return [String]
|
@@ -62,25 +63,26 @@ module Google
|
|
62
63
|
# @note Direction instantion is discouraged to avoid embedding IDs
|
63
64
|
# & secrets in source. See {#from_file} to load from
|
64
65
|
# `client_secrets.json` files.
|
65
|
-
def initialize
|
66
|
-
|
67
|
-
|
66
|
+
def initialize id, secret
|
67
|
+
CredentialsLoader.warn_if_cloud_sdk_credentials id
|
68
|
+
raise "Client id can not be nil" if id.nil?
|
69
|
+
raise "Client secret can not be nil" if secret.nil?
|
68
70
|
@id = id
|
69
71
|
@secret = secret
|
70
72
|
end
|
71
73
|
|
72
|
-
# Constructs a Client ID from a JSON file
|
74
|
+
# Constructs a Client ID from a JSON file downloaded from the
|
73
75
|
# Google Developers Console.
|
74
76
|
#
|
75
77
|
# @param [String, File] file
|
76
78
|
# Path of file to read from
|
77
79
|
# @return [Google::Auth::ClientID]
|
78
|
-
def self.from_file
|
79
|
-
|
80
|
-
File.open
|
80
|
+
def self.from_file file
|
81
|
+
raise "File can not be nil." if file.nil?
|
82
|
+
File.open file.to_s do |f|
|
81
83
|
json = f.read
|
82
|
-
config = MultiJson.load
|
83
|
-
from_hash
|
84
|
+
config = MultiJson.load json
|
85
|
+
from_hash config
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
@@ -91,11 +93,11 @@ module Google
|
|
91
93
|
# @param [hash] config
|
92
94
|
# Parsed contents of the JSON file
|
93
95
|
# @return [Google::Auth::ClientID]
|
94
|
-
def self.from_hash
|
95
|
-
|
96
|
+
def self.from_hash config
|
97
|
+
raise "Hash can not be nil." if config.nil?
|
96
98
|
raw_detail = config[INSTALLED_APP] || config[WEB_APP]
|
97
|
-
|
98
|
-
ClientId.new
|
99
|
+
raise MISSING_TOP_LEVEL_ELEMENT_ERROR if raw_detail.nil?
|
100
|
+
ClientId.new raw_detail[CLIENT_ID], raw_detail[CLIENT_SECRET]
|
99
101
|
end
|
100
102
|
end
|
101
103
|
end
|
@@ -27,57 +27,74 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
30
|
+
require "faraday"
|
31
|
+
require "googleauth/signet"
|
32
|
+
require "memoist"
|
33
33
|
|
34
34
|
module Google
|
35
35
|
# Module Auth provides classes that provide Google-specific authorization
|
36
36
|
# used to access Google APIs.
|
37
37
|
module Auth
|
38
|
-
NO_METADATA_SERVER_ERROR =
|
39
|
-
Error code 404 trying to get security access token
|
40
|
-
from Compute Engine metadata for the default service account. This
|
41
|
-
may be because the virtual machine instance does not have permission
|
42
|
-
scopes specified.
|
43
|
-
|
44
|
-
UNEXPECTED_ERROR_SUFFIX =
|
45
|
-
trying to get security access token from Compute Engine metadata for
|
46
|
-
the default service account
|
47
|
-
|
38
|
+
NO_METADATA_SERVER_ERROR = <<~ERROR.freeze
|
39
|
+
Error code 404 trying to get security access token
|
40
|
+
from Compute Engine metadata for the default service account. This
|
41
|
+
may be because the virtual machine instance does not have permission
|
42
|
+
scopes specified.
|
43
|
+
ERROR
|
44
|
+
UNEXPECTED_ERROR_SUFFIX = <<~ERROR.freeze
|
45
|
+
trying to get security access token from Compute Engine metadata for
|
46
|
+
the default service account
|
47
|
+
ERROR
|
48
48
|
|
49
49
|
# Extends Signet::OAuth2::Client so that the auth token is obtained from
|
50
50
|
# the GCE metadata server.
|
51
51
|
class GCECredentials < Signet::OAuth2::Client
|
52
52
|
# The IP Address is used in the URIs to speed up failures on non-GCE
|
53
53
|
# systems.
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
DEFAULT_METADATA_HOST = "169.254.169.254".freeze
|
55
|
+
|
56
|
+
# @private Unused and deprecated
|
57
|
+
COMPUTE_AUTH_TOKEN_URI =
|
58
|
+
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
|
59
|
+
# @private Unused and deprecated
|
60
|
+
COMPUTE_ID_TOKEN_URI =
|
61
|
+
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity".freeze
|
62
|
+
# @private Unused and deprecated
|
63
|
+
COMPUTE_CHECK_URI = "http://169.254.169.254".freeze
|
57
64
|
|
58
65
|
class << self
|
59
66
|
extend Memoist
|
60
67
|
|
68
|
+
def metadata_host
|
69
|
+
ENV.fetch "GCE_METADATA_HOST", DEFAULT_METADATA_HOST
|
70
|
+
end
|
71
|
+
|
72
|
+
def compute_check_uri
|
73
|
+
"http://#{metadata_host}".freeze
|
74
|
+
end
|
75
|
+
|
76
|
+
def compute_auth_token_uri
|
77
|
+
"#{compute_check_uri}/computeMetadata/v1/instance/service-accounts/default/token".freeze
|
78
|
+
end
|
79
|
+
|
80
|
+
def compute_id_token_uri
|
81
|
+
"#{compute_check_uri}/computeMetadata/v1/instance/service-accounts/default/identity".freeze
|
82
|
+
end
|
83
|
+
|
61
84
|
# Detect if this appear to be a GCE instance, by checking if metadata
|
62
|
-
# is available
|
63
|
-
def on_gce?
|
85
|
+
# is available.
|
86
|
+
def on_gce? options = {}
|
87
|
+
# TODO: This should use google-cloud-env instead.
|
64
88
|
c = options[:connection] || Faraday.default_connection
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# issue is that resolving an unknown host on some networks will take
|
70
|
-
# 20-30 seconds; making this timeout short fixes the issue, but
|
71
|
-
# could lead to false negatives in the event that we are on GCE, but
|
72
|
-
# the metadata resolution was particularly slow. The latter case is
|
73
|
-
# "unlikely".
|
74
|
-
req.options.timeout = 0.1
|
89
|
+
headers = { "Metadata-Flavor" => "Google" }
|
90
|
+
resp = c.get compute_check_uri, nil, headers do |req|
|
91
|
+
req.options.timeout = 1.0
|
92
|
+
req.options.open_timeout = 0.1
|
75
93
|
end
|
76
94
|
return false unless resp.status == 200
|
77
|
-
|
78
|
-
return resp.headers['Metadata-Flavor'] == 'Google'
|
95
|
+
resp.headers["Metadata-Flavor"] == "Google"
|
79
96
|
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
80
|
-
|
97
|
+
false
|
81
98
|
end
|
82
99
|
|
83
100
|
memoize :on_gce?
|
@@ -85,19 +102,29 @@ END
|
|
85
102
|
|
86
103
|
# Overrides the super class method to change how access tokens are
|
87
104
|
# fetched.
|
88
|
-
def fetch_access_token
|
105
|
+
def fetch_access_token options = {}
|
89
106
|
c = options[:connection] || Faraday.default_connection
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
retry_with_error do
|
108
|
+
uri = target_audience ? GCECredentials.compute_id_token_uri : GCECredentials.compute_auth_token_uri
|
109
|
+
query = target_audience ? { "audience" => target_audience, "format" => "full" } : {}
|
110
|
+
query[:scopes] = Array(scope).join "," if scope
|
111
|
+
headers = { "Metadata-Flavor" => "Google" }
|
112
|
+
resp = c.get uri, query, headers
|
113
|
+
case resp.status
|
114
|
+
when 200
|
115
|
+
content_type = resp.headers["content-type"]
|
116
|
+
if content_type == "text/html"
|
117
|
+
{ (target_audience ? "id_token" : "access_token") => resp.body }
|
118
|
+
else
|
119
|
+
Signet::OAuth2.parse_credentials resp.body, content_type
|
120
|
+
end
|
121
|
+
when 404
|
122
|
+
raise Signet::AuthorizationError, NO_METADATA_SERVER_ERROR
|
123
|
+
else
|
124
|
+
msg = "Unexpected error code #{resp.status}" \
|
125
|
+
"#{UNEXPECTED_ERROR_SUFFIX}"
|
126
|
+
raise Signet::AuthorizationError, msg
|
127
|
+
end
|
101
128
|
end
|
102
129
|
end
|
103
130
|
end
|