googleauth 0.8.0 → 0.8.1
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 +4 -4
- data/.kokoro/build.sh +2 -34
- data/.kokoro/continuous/common.cfg +5 -0
- data/.kokoro/continuous/linux.cfg +1 -1
- data/.kokoro/osx.sh +2 -33
- data/.kokoro/presubmit/common.cfg +5 -0
- data/.kokoro/presubmit/linux.cfg +1 -1
- data/.kokoro/release.cfg +53 -0
- data/.kokoro/trampoline.sh +3 -23
- data/.kokoro/windows.sh +2 -30
- data/.rubocop.yml +7 -24
- data/CHANGELOG.md +24 -39
- data/Gemfile +14 -14
- data/README.md +21 -1
- data/Rakefile +84 -10
- data/googleauth.gemspec +23 -23
- data/lib/googleauth.rb +6 -6
- data/lib/googleauth/application_default.rb +11 -11
- data/lib/googleauth/client_id.rb +16 -16
- data/lib/googleauth/compute_engine.rb +27 -27
- data/lib/googleauth/credentials.rb +35 -37
- data/lib/googleauth/credentials_loader.rb +64 -67
- data/lib/googleauth/default_credentials.rb +18 -18
- data/lib/googleauth/iam.rb +9 -9
- data/lib/googleauth/json_key_reader.rb +6 -6
- data/lib/googleauth/scope_util.rb +11 -11
- data/lib/googleauth/service_account.rb +42 -42
- data/lib/googleauth/signet.rb +15 -17
- data/lib/googleauth/stores/file_token_store.rb +8 -8
- data/lib/googleauth/stores/redis_token_store.rb +17 -17
- data/lib/googleauth/token_store.rb +6 -6
- data/lib/googleauth/user_authorizer.rb +55 -59
- data/lib/googleauth/user_refresh.rb +27 -27
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +55 -56
- data/spec/googleauth/apply_auth_examples.rb +46 -46
- data/spec/googleauth/client_id_spec.rb +54 -54
- data/spec/googleauth/compute_engine_spec.rb +41 -41
- data/spec/googleauth/credentials_spec.rb +97 -97
- data/spec/googleauth/get_application_default_spec.rb +114 -114
- data/spec/googleauth/iam_spec.rb +25 -25
- data/spec/googleauth/scope_util_spec.rb +24 -24
- data/spec/googleauth/service_account_spec.rb +204 -194
- data/spec/googleauth/signet_spec.rb +37 -38
- data/spec/googleauth/stores/file_token_store_spec.rb +12 -12
- 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 +120 -121
- data/spec/googleauth/user_refresh_spec.rb +151 -146
- data/spec/googleauth/web_user_authorizer_spec.rb +66 -66
- data/spec/spec_helper.rb +19 -19
- metadata +4 -6
- data/.kokoro/common.cfg +0 -22
- data/.travis.yml +0 -40
data/README.md
CHANGED
|
@@ -138,7 +138,7 @@ scope = 'https://www.googleapis.com/auth/androidpublisher'
|
|
|
138
138
|
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
|
|
139
139
|
json_key_io: File.open('/path/to/service_account_json_key.json'),
|
|
140
140
|
scope: scope)
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
authorizer.fetch_access_token!
|
|
143
143
|
```
|
|
144
144
|
|
|
@@ -151,6 +151,26 @@ export GOOGLE_CLIENT_EMAIL=xxxx@xxxx.iam.gserviceaccount.com
|
|
|
151
151
|
export GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
```ruby
|
|
155
|
+
require 'googleauth'
|
|
156
|
+
require 'google/apis/drive_v3'
|
|
157
|
+
|
|
158
|
+
Drive = ::Google::Apis::DriveV3
|
|
159
|
+
drive = Drive::DriveService.new
|
|
160
|
+
|
|
161
|
+
# Auths with ENV vars:
|
|
162
|
+
# "GOOGLE_CLIENT_ID",
|
|
163
|
+
# "GOOGLE_CLIENT_EMAIL",
|
|
164
|
+
# "GOOGLE_ACCOUNT_TYPE",
|
|
165
|
+
# "GOOGLE_PRIVATE_KEY"
|
|
166
|
+
auth = ::Google::Auth::ServiceAccountCredentials
|
|
167
|
+
.make_creds(scope: 'https://www.googleapis.com/auth/drive')
|
|
168
|
+
drive.authorization = auth
|
|
169
|
+
|
|
170
|
+
list_files = drive.list_files()
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
|
|
154
174
|
### Storage
|
|
155
175
|
|
|
156
176
|
Authorizers require a storage instance to manage long term persistence of
|
data/Rakefile
CHANGED
|
@@ -1,15 +1,89 @@
|
|
|
1
1
|
# -*- ruby -*-
|
|
2
|
-
require
|
|
3
|
-
require 'rubocop/rake_task'
|
|
4
|
-
require 'bundler/gem_tasks'
|
|
2
|
+
require "bundler/gem_tasks"
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
task :ci do
|
|
5
|
+
header "Using Ruby - #{RUBY_VERSION}"
|
|
6
|
+
sh "bundle exec rubocop"
|
|
7
|
+
sh "bundle exec rspec"
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
task :release, :tag do |_t, args|
|
|
11
|
+
tag = args[:tag]
|
|
12
|
+
raise "You must provide a tag to release." if tag.nil?
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
# Verify the tag format "vVERSION"
|
|
15
|
+
m = tag.match(/v(?<version>\S*)/)
|
|
16
|
+
raise "Tag #{tag} does not match the expected format." if m.nil?
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
version = m[:version]
|
|
19
|
+
raise "You must provide a version." if version.nil?
|
|
20
|
+
|
|
21
|
+
api_token = ENV["RUBYGEMS_API_TOKEN"]
|
|
22
|
+
|
|
23
|
+
require "gems"
|
|
24
|
+
if api_token
|
|
25
|
+
::Gems.configure do |config|
|
|
26
|
+
config.key = api_token
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Bundler.with_clean_env do
|
|
31
|
+
sh "rm -rf pkg"
|
|
32
|
+
sh "bundle update"
|
|
33
|
+
sh "bundle exec rake build"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
path_to_be_pushed = "pkg/#{version}.gem"
|
|
37
|
+
if File.file? path_to_be_pushed
|
|
38
|
+
begin
|
|
39
|
+
::Gems.push File.new(path_to_be_pushed)
|
|
40
|
+
puts "Successfully built and pushed googleauth for version #{version}"
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
puts "Error while releasing googleauth version #{version}: #{e.message}"
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
raise "Cannot build googleauth for version #{version}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
namespace :kokoro do
|
|
50
|
+
task :load_env_vars do
|
|
51
|
+
service_account = "#{ENV['KOKORO_GFILE_DIR']}/service-account.json"
|
|
52
|
+
ENV["GOOGLE_APPLICATION_CREDENTIALS"] = service_account
|
|
53
|
+
filename = "#{ENV['KOKORO_GFILE_DIR']}/env_vars.json"
|
|
54
|
+
env_vars = JSON.parse File.read(filename)
|
|
55
|
+
env_vars.each { |k, v| ENV[k] = v }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
task :presubmit do
|
|
59
|
+
Rake::Task["ci"].invoke
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
task :continuous do
|
|
63
|
+
Rake::Task["ci"].invoke
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
task :nightly do
|
|
67
|
+
Rake::Task["ci"].invoke
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
task :release do
|
|
71
|
+
version = "0.1.0"
|
|
72
|
+
Bundler.with_clean_env do
|
|
73
|
+
version = `bundle exec gem list`
|
|
74
|
+
.split("\n").select { |line| line.include? "googleauth" }
|
|
75
|
+
.first.split("(").last.split(")").first || "0.1.0"
|
|
76
|
+
end
|
|
77
|
+
Rake::Task["kokoro:load_env_vars"].invoke
|
|
78
|
+
Rake::Task["release"].invoke "v/#{version}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def header str, token = "#"
|
|
83
|
+
line_length = str.length + 8
|
|
84
|
+
puts ""
|
|
85
|
+
puts token * line_length
|
|
86
|
+
puts "#{token * 3} #{str} #{token * 3}"
|
|
87
|
+
puts token * line_length
|
|
88
|
+
puts ""
|
|
89
|
+
end
|
data/googleauth.gemspec
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# -*- ruby -*-
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
|
-
$LOAD_PATH.push File.expand_path(
|
|
5
|
-
require
|
|
4
|
+
$LOAD_PATH.push File.expand_path("lib", __dir__)
|
|
5
|
+
require "googleauth/version"
|
|
6
6
|
|
|
7
|
-
Gem::Specification.new do |
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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/google/google-auth-library-ruby"
|
|
13
|
+
gem.summary = "Google Auth Library for Ruby"
|
|
14
|
+
gem.license = "Apache-2.0"
|
|
15
|
+
gem.description = <<-DESCRIPTION
|
|
16
16
|
Allows simple authorization for accessing Google APIs.
|
|
17
17
|
Provide support for Application Default Credentials, as described at
|
|
18
18
|
https://developers.google.com/accounts/docs/application-default-credentials
|
|
19
19
|
DESCRIPTION
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
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
|
|
25
25
|
end
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
gem.require_paths = ["lib"]
|
|
27
|
+
gem.platform = Gem::Platform::RUBY
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
gem.add_dependency "faraday", "~> 0.12"
|
|
30
|
+
gem.add_dependency "jwt", ">= 1.4", "< 3.0"
|
|
31
|
+
gem.add_dependency "memoist", "~> 0.16"
|
|
32
|
+
gem.add_dependency "multi_json", "~> 1.11"
|
|
33
|
+
gem.add_dependency "os", ">= 0.9", "< 2.0"
|
|
34
|
+
gem.add_dependency "signet", "~> 0.7"
|
|
35
35
|
end
|
data/lib/googleauth.rb
CHANGED
|
@@ -27,9 +27,9 @@
|
|
|
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
|
|
33
|
-
require
|
|
34
|
-
require
|
|
35
|
-
require
|
|
30
|
+
require "googleauth/application_default"
|
|
31
|
+
require "googleauth/client_id"
|
|
32
|
+
require "googleauth/credentials"
|
|
33
|
+
require "googleauth/default_credentials"
|
|
34
|
+
require "googleauth/user_authorizer"
|
|
35
|
+
require "googleauth/web_user_authorizer"
|
|
@@ -27,18 +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
|
|
31
|
-
require
|
|
30
|
+
require "googleauth/compute_engine"
|
|
31
|
+
require "googleauth/default_credentials"
|
|
32
32
|
|
|
33
33
|
module Google
|
|
34
34
|
# Module Auth provides classes that provide Google-specific authorization
|
|
35
35
|
# used to access Google APIs.
|
|
36
36
|
module Auth
|
|
37
|
-
NOT_FOUND_ERROR =
|
|
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
|
|
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
|
|
42
44
|
|
|
43
45
|
# Obtains the default credentials implementation to use in this
|
|
44
46
|
# environment.
|
|
@@ -63,19 +65,17 @@ ERROR_MESSAGE
|
|
|
63
65
|
# connection to use for token refresh requests.
|
|
64
66
|
# * `:connection` The connection to use to determine whether GCE
|
|
65
67
|
# metadata credentials are available.
|
|
66
|
-
def get_application_default
|
|
68
|
+
def get_application_default scope = nil, options = {}
|
|
67
69
|
creds = DefaultCredentials.from_env(scope, options) ||
|
|
68
70
|
DefaultCredentials.from_well_known_path(scope, options) ||
|
|
69
71
|
DefaultCredentials.from_system_default_path(scope, options)
|
|
70
72
|
return creds unless creds.nil?
|
|
71
|
-
unless GCECredentials.on_gce?
|
|
73
|
+
unless GCECredentials.on_gce? options
|
|
72
74
|
# Clear cache of the result of GCECredentials.on_gce?
|
|
73
75
|
GCECredentials.unmemoize_all
|
|
74
76
|
raise NOT_FOUND_ERROR
|
|
75
77
|
end
|
|
76
78
|
GCECredentials.new
|
|
77
79
|
end
|
|
78
|
-
|
|
79
|
-
module_function :get_application_default
|
|
80
80
|
end
|
|
81
81
|
end
|
data/lib/googleauth/client_id.rb
CHANGED
|
@@ -27,18 +27,18 @@
|
|
|
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
|
|
30
|
+
require "multi_json"
|
|
31
|
+
require "googleauth/credentials_loader"
|
|
32
32
|
|
|
33
33
|
module Google
|
|
34
34
|
module Auth
|
|
35
35
|
# Representation of an application's identity for user authorization
|
|
36
36
|
# flows.
|
|
37
37
|
class ClientId
|
|
38
|
-
INSTALLED_APP =
|
|
39
|
-
WEB_APP =
|
|
40
|
-
CLIENT_ID =
|
|
41
|
-
CLIENT_SECRET =
|
|
38
|
+
INSTALLED_APP = "installed".freeze
|
|
39
|
+
WEB_APP = "web".freeze
|
|
40
|
+
CLIENT_ID = "client_id".freeze
|
|
41
|
+
CLIENT_SECRET = "client_secret".freeze
|
|
42
42
|
MISSING_TOP_LEVEL_ELEMENT_ERROR =
|
|
43
43
|
"Expected top level property 'installed' or 'web' to be present.".freeze
|
|
44
44
|
|
|
@@ -63,10 +63,10 @@ module Google
|
|
|
63
63
|
# @note Direction instantion is discouraged to avoid embedding IDs
|
|
64
64
|
# & secrets in source. See {#from_file} to load from
|
|
65
65
|
# `client_secrets.json` files.
|
|
66
|
-
def initialize
|
|
66
|
+
def initialize id, secret
|
|
67
67
|
CredentialsLoader.warn_if_cloud_sdk_credentials id
|
|
68
|
-
raise
|
|
69
|
-
raise
|
|
68
|
+
raise "Client id can not be nil" if id.nil?
|
|
69
|
+
raise "Client secret can not be nil" if secret.nil?
|
|
70
70
|
@id = id
|
|
71
71
|
@secret = secret
|
|
72
72
|
end
|
|
@@ -77,12 +77,12 @@ module Google
|
|
|
77
77
|
# @param [String, File] file
|
|
78
78
|
# Path of file to read from
|
|
79
79
|
# @return [Google::Auth::ClientID]
|
|
80
|
-
def self.from_file
|
|
81
|
-
raise
|
|
82
|
-
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|
|
|
83
83
|
json = f.read
|
|
84
84
|
config = MultiJson.load json
|
|
85
|
-
from_hash
|
|
85
|
+
from_hash config
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
@@ -93,11 +93,11 @@ module Google
|
|
|
93
93
|
# @param [hash] config
|
|
94
94
|
# Parsed contents of the JSON file
|
|
95
95
|
# @return [Google::Auth::ClientID]
|
|
96
|
-
def self.from_hash
|
|
97
|
-
raise
|
|
96
|
+
def self.from_hash config
|
|
97
|
+
raise "Hash can not be nil." if config.nil?
|
|
98
98
|
raw_detail = config[INSTALLED_APP] || config[WEB_APP]
|
|
99
99
|
raise MISSING_TOP_LEVEL_ELEMENT_ERROR if raw_detail.nil?
|
|
100
|
-
ClientId.new
|
|
100
|
+
ClientId.new raw_detail[CLIENT_ID], raw_detail[CLIENT_SECRET]
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
end
|
|
@@ -27,42 +27,42 @@
|
|
|
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
|
-
ERROR
|
|
44
|
-
UNEXPECTED_ERROR_SUFFIX =
|
|
45
|
-
trying to get security access token from Compute Engine metadata for
|
|
46
|
-
the default service account
|
|
47
|
-
ERROR
|
|
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
|
-
COMPUTE_AUTH_TOKEN_URI =
|
|
55
|
-
|
|
56
|
-
COMPUTE_CHECK_URI =
|
|
54
|
+
COMPUTE_AUTH_TOKEN_URI = "http://169.254.169.254/computeMetadata/v1/"\
|
|
55
|
+
"instance/service-accounts/default/token".freeze
|
|
56
|
+
COMPUTE_CHECK_URI = "http://169.254.169.254".freeze
|
|
57
57
|
|
|
58
58
|
class << self
|
|
59
59
|
extend Memoist
|
|
60
60
|
|
|
61
61
|
# Detect if this appear to be a GCE instance, by checking if metadata
|
|
62
62
|
# is available
|
|
63
|
-
def on_gce?
|
|
63
|
+
def on_gce? options = {}
|
|
64
64
|
c = options[:connection] || Faraday.default_connection
|
|
65
|
-
resp = c.get
|
|
65
|
+
resp = c.get COMPUTE_CHECK_URI do |req|
|
|
66
66
|
# Comment from: oauth2client/client.py
|
|
67
67
|
#
|
|
68
68
|
# Note: the explicit `timeout` below is a workaround. The underlying
|
|
@@ -74,10 +74,10 @@ ERROR
|
|
|
74
74
|
req.options.timeout = 0.1
|
|
75
75
|
end
|
|
76
76
|
return false unless resp.status == 200
|
|
77
|
-
return false unless resp.headers.key?
|
|
78
|
-
|
|
77
|
+
return false unless resp.headers.key? "Metadata-Flavor"
|
|
78
|
+
resp.headers["Metadata-Flavor"] == "Google"
|
|
79
79
|
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
|
80
|
-
|
|
80
|
+
false
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
memoize :on_gce?
|
|
@@ -85,21 +85,21 @@ ERROR
|
|
|
85
85
|
|
|
86
86
|
# Overrides the super class method to change how access tokens are
|
|
87
87
|
# fetched.
|
|
88
|
-
def fetch_access_token
|
|
88
|
+
def fetch_access_token options = {}
|
|
89
89
|
c = options[:connection] || Faraday.default_connection
|
|
90
90
|
retry_with_error do
|
|
91
|
-
headers = {
|
|
92
|
-
resp = c.get
|
|
91
|
+
headers = { "Metadata-Flavor" => "Google" }
|
|
92
|
+
resp = c.get COMPUTE_AUTH_TOKEN_URI, nil, headers
|
|
93
93
|
case resp.status
|
|
94
94
|
when 200
|
|
95
95
|
Signet::OAuth2.parse_credentials(resp.body,
|
|
96
|
-
resp.headers[
|
|
96
|
+
resp.headers["content-type"])
|
|
97
97
|
when 404
|
|
98
|
-
raise
|
|
98
|
+
raise Signet::AuthorizationError, NO_METADATA_SERVER_ERROR
|
|
99
99
|
else
|
|
100
100
|
msg = "Unexpected error code #{resp.status}" \
|
|
101
101
|
"#{UNEXPECTED_ERROR_SUFFIX}"
|
|
102
|
-
raise
|
|
102
|
+
raise Signet::AuthorizationError, msg
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
end
|
|
@@ -27,21 +27,19 @@
|
|
|
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
|
-
|
|
30
|
+
require "forwardable"
|
|
31
|
+
require "json"
|
|
32
|
+
require "signet/oauth_2/client"
|
|
31
33
|
|
|
32
|
-
require
|
|
33
|
-
require 'json'
|
|
34
|
-
require 'signet/oauth_2/client'
|
|
35
|
-
|
|
36
|
-
require 'googleauth/credentials_loader'
|
|
34
|
+
require "googleauth/credentials_loader"
|
|
37
35
|
|
|
38
36
|
module Google
|
|
39
37
|
module Auth
|
|
40
38
|
# This class is intended to be inherited by API-specific classes
|
|
41
39
|
# which overrides the SCOPE constant.
|
|
42
40
|
class Credentials
|
|
43
|
-
TOKEN_CREDENTIAL_URI =
|
|
44
|
-
AUDIENCE =
|
|
41
|
+
TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token".freeze
|
|
42
|
+
AUDIENCE = "https://oauth2.googleapis.com/token".freeze
|
|
45
43
|
SCOPE = [].freeze
|
|
46
44
|
PATH_ENV_VARS = [].freeze
|
|
47
45
|
JSON_ENV_VARS = [].freeze
|
|
@@ -56,35 +54,37 @@ module Google
|
|
|
56
54
|
:token_credential_uri, :audience,
|
|
57
55
|
:scope, :issuer, :signing_key, :updater_proc
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
# rubocop:disable Metrics/AbcSize
|
|
58
|
+
def initialize keyfile, options = {}
|
|
60
59
|
scope = options[:scope]
|
|
61
60
|
verify_keyfile_provided! keyfile
|
|
62
|
-
@project_id = options[
|
|
61
|
+
@project_id = options["project_id"] || options["project"]
|
|
63
62
|
if keyfile.is_a? Signet::OAuth2::Client
|
|
64
63
|
@client = keyfile
|
|
65
64
|
@project_id ||= keyfile.project_id if keyfile.respond_to? :project_id
|
|
66
65
|
elsif keyfile.is_a? Hash
|
|
67
66
|
hash = stringify_hash_keys keyfile
|
|
68
|
-
hash[
|
|
67
|
+
hash["scope"] ||= scope
|
|
69
68
|
@client = init_client hash, options
|
|
70
|
-
@project_id ||= (hash[
|
|
69
|
+
@project_id ||= (hash["project_id"] || hash["project"])
|
|
71
70
|
else
|
|
72
71
|
verify_keyfile_exists! keyfile
|
|
73
72
|
json = JSON.parse ::File.read(keyfile)
|
|
74
|
-
json[
|
|
75
|
-
@project_id ||= (json[
|
|
73
|
+
json["scope"] ||= scope
|
|
74
|
+
@project_id ||= (json["project_id"] || json["project"])
|
|
76
75
|
@client = init_client json, options
|
|
77
76
|
end
|
|
78
77
|
CredentialsLoader.warn_if_cloud_sdk_credentials @client.client_id
|
|
79
78
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
|
80
79
|
@client.fetch_access_token!
|
|
81
80
|
end
|
|
81
|
+
# rubocop:enable Metrics/AbcSize
|
|
82
82
|
|
|
83
83
|
# Returns the default credentials checking, in this order, the path env
|
|
84
84
|
# evironment variables, json environment variables, default paths. If the
|
|
85
85
|
# previously stated locations do not contain keyfile information,
|
|
86
86
|
# this method defaults to use the application default.
|
|
87
|
-
def self.default
|
|
87
|
+
def self.default options = {}
|
|
88
88
|
# First try to find keyfile file from environment variables.
|
|
89
89
|
client = from_path_vars options
|
|
90
90
|
|
|
@@ -99,7 +99,7 @@ module Google
|
|
|
99
99
|
client
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
def self.from_path_vars
|
|
102
|
+
def self.from_path_vars options
|
|
103
103
|
self::PATH_ENV_VARS
|
|
104
104
|
.map { |v| ENV[v] }
|
|
105
105
|
.compact
|
|
@@ -110,23 +110,21 @@ module Google
|
|
|
110
110
|
nil
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
def self.from_json_vars
|
|
113
|
+
def self.from_json_vars options
|
|
114
114
|
json = lambda do |v|
|
|
115
115
|
unless ENV[v].nil?
|
|
116
116
|
begin
|
|
117
117
|
JSON.parse ENV[v]
|
|
118
|
-
rescue
|
|
118
|
+
rescue StandardError
|
|
119
119
|
nil
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
|
-
self::JSON_ENV_VARS.map(&json).compact.each
|
|
124
|
-
return new hash, options
|
|
125
|
-
end
|
|
123
|
+
self::JSON_ENV_VARS.map(&json).compact.each { |hash| return new hash, options }
|
|
126
124
|
nil
|
|
127
125
|
end
|
|
128
126
|
|
|
129
|
-
def self.from_default_paths
|
|
127
|
+
def self.from_default_paths options
|
|
130
128
|
self::DEFAULT_PATHS
|
|
131
129
|
.select { |p| ::File.file? p }
|
|
132
130
|
.each do |file|
|
|
@@ -135,7 +133,7 @@ module Google
|
|
|
135
133
|
nil
|
|
136
134
|
end
|
|
137
135
|
|
|
138
|
-
def self.from_application_default
|
|
136
|
+
def self.from_application_default options
|
|
139
137
|
scope = options[:scope] || self::SCOPE
|
|
140
138
|
client = Google::Auth.get_application_default scope
|
|
141
139
|
new client, options
|
|
@@ -148,41 +146,41 @@ module Google
|
|
|
148
146
|
protected
|
|
149
147
|
|
|
150
148
|
# Verify that the keyfile argument is provided.
|
|
151
|
-
def verify_keyfile_provided!
|
|
149
|
+
def verify_keyfile_provided! keyfile
|
|
152
150
|
return unless keyfile.nil?
|
|
153
|
-
raise
|
|
151
|
+
raise "The keyfile passed to Google::Auth::Credentials.new was nil."
|
|
154
152
|
end
|
|
155
153
|
|
|
156
154
|
# Verify that the keyfile argument is a file.
|
|
157
|
-
def verify_keyfile_exists!
|
|
155
|
+
def verify_keyfile_exists! keyfile
|
|
158
156
|
exists = ::File.file? keyfile
|
|
159
157
|
raise "The keyfile '#{keyfile}' is not a valid file." unless exists
|
|
160
158
|
end
|
|
161
159
|
|
|
162
160
|
# Initializes the Signet client.
|
|
163
|
-
def init_client
|
|
161
|
+
def init_client keyfile, connection_options = {}
|
|
164
162
|
client_opts = client_options keyfile
|
|
165
163
|
Signet::OAuth2::Client.new(client_opts)
|
|
166
164
|
.configure_connection(connection_options)
|
|
167
165
|
end
|
|
168
166
|
|
|
169
167
|
# returns a new Hash with string keys instead of symbol keys.
|
|
170
|
-
def stringify_hash_keys
|
|
168
|
+
def stringify_hash_keys hash
|
|
171
169
|
Hash[hash.map { |k, v| [k.to_s, v] }]
|
|
172
170
|
end
|
|
173
171
|
|
|
174
|
-
def client_options
|
|
172
|
+
def client_options options
|
|
175
173
|
# Keyfile options have higher priority over constructor defaults
|
|
176
|
-
options[
|
|
177
|
-
options[
|
|
178
|
-
options[
|
|
174
|
+
options["token_credential_uri"] ||= self.class::TOKEN_CREDENTIAL_URI
|
|
175
|
+
options["audience"] ||= self.class::AUDIENCE
|
|
176
|
+
options["scope"] ||= self.class::SCOPE
|
|
179
177
|
|
|
180
178
|
# client options for initializing signet client
|
|
181
|
-
{ token_credential_uri: options[
|
|
182
|
-
audience:
|
|
183
|
-
scope:
|
|
184
|
-
issuer:
|
|
185
|
-
signing_key:
|
|
179
|
+
{ token_credential_uri: options["token_credential_uri"],
|
|
180
|
+
audience: options["audience"],
|
|
181
|
+
scope: Array(options["scope"]),
|
|
182
|
+
issuer: options["client_email"],
|
|
183
|
+
signing_key: OpenSSL::PKey::RSA.new(options["private_key"]) }
|
|
186
184
|
end
|
|
187
185
|
end
|
|
188
186
|
end
|