googleauth 0.5.1 → 0.11.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/{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 +17 -1
- data/CHANGELOG.md +90 -19
- data/CODE_OF_CONDUCT.md +43 -0
- data/Gemfile +16 -13
- data/README.md +58 -18
- data/Rakefile +106 -10
- data/googleauth.gemspec +27 -25
- data/lib/googleauth/application_default.rb +81 -0
- data/lib/googleauth/client_id.rb +21 -19
- data/lib/googleauth/compute_engine.rb +40 -43
- data/lib/googleauth/credentials.rb +375 -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/json_key_reader.rb +46 -0
- data/lib/googleauth/scope_util.rb +12 -12
- data/lib/googleauth/service_account.rb +64 -62
- data/lib/googleauth/signet.rb +53 -12
- 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/lib/googleauth.rb +6 -96
- 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 +47 -46
- data/spec/googleauth/client_id_spec.rb +75 -55
- data/spec/googleauth/compute_engine_spec.rb +60 -43
- data/spec/googleauth/credentials_spec.rb +467 -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 +261 -143
- data/spec/googleauth/signet_spec.rb +93 -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
- metadata +75 -32
- data/.rubocop_todo.yml +0 -32
- data/.travis.yml +0 -37
data/Gemfile
CHANGED
@@ -1,24 +1,27 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in googleauth.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :development do
|
7
|
-
gem
|
8
|
-
gem
|
9
|
-
gem
|
10
|
-
gem
|
11
|
-
gem
|
12
|
-
gem
|
13
|
-
gem
|
14
|
-
gem
|
15
|
-
gem
|
16
|
-
gem
|
17
|
-
gem
|
18
|
-
gem
|
7
|
+
gem "bundler", ">= 1.9"
|
8
|
+
gem "coveralls", "~> 0.7"
|
9
|
+
gem "fakefs", "~> 0.6"
|
10
|
+
gem "fakeredis", "~> 0.5"
|
11
|
+
gem "google-style", "~> 1.24.0"
|
12
|
+
gem "logging", "~> 2.0"
|
13
|
+
gem "rack-test", "~> 0.6"
|
14
|
+
gem "rake", "~> 10.0"
|
15
|
+
gem "redis", "~> 3.2"
|
16
|
+
gem "rspec", "~> 3.0"
|
17
|
+
gem "simplecov", "~> 0.9"
|
18
|
+
gem "sinatra"
|
19
|
+
gem "webmock", "~> 1.21"
|
19
20
|
end
|
20
21
|
|
21
22
|
platforms :jruby do
|
22
23
|
group :development do
|
23
24
|
end
|
24
25
|
end
|
26
|
+
|
27
|
+
gem "gems", "~> 1.2"
|
data/README.md
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
# Google Auth Library for Ruby
|
2
2
|
|
3
3
|
<dl>
|
4
|
-
<dt>Homepage</dt><dd><a href="http://www.github.com/
|
4
|
+
<dt>Homepage</dt><dd><a href="http://www.github.com/googleapis/google-auth-library-ruby">http://www.github.com/googleapis/google-auth-library-ruby</a></dd>
|
5
5
|
<dt>Authors</dt><dd><a href="mailto:temiola@google.com">Tim Emiola</a></dd>
|
6
6
|
<dt>Copyright</dt><dd>Copyright © 2015 Google, Inc.</dd>
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
8
8
|
</dl>
|
9
9
|
|
10
10
|
[](http://badge.fury.io/rb/googleauth)
|
11
|
-
[](http://travis-ci.org/google/google-auth-library-ruby)
|
12
|
-
[](https://coveralls.io/r/google/google-auth-library-ruby)
|
13
|
-
[](https://gemnasium.com/google/google-auth-library-ruby)
|
14
11
|
|
15
12
|
## Description
|
16
13
|
|
@@ -70,7 +67,7 @@ a generic authorizer useful for command line apps or custom integrations as
|
|
70
67
|
well as a web variant tailored toward Rack-based applications.
|
71
68
|
|
72
69
|
The authorizers are intended for authorization use cases. For sign-on,
|
73
|
-
see [Google
|
70
|
+
see [Google Identity Platform](https://developers.google.com/identity/)
|
74
71
|
|
75
72
|
### Example (Web)
|
76
73
|
|
@@ -92,7 +89,7 @@ get('/authorize') do
|
|
92
89
|
user_id = request.session['user_id']
|
93
90
|
credentials = authorizer.get_credentials(user_id, request)
|
94
91
|
if credentials.nil?
|
95
|
-
redirect authorizer.get_authorization_url(
|
92
|
+
redirect authorizer.get_authorization_url(login_hint: user_id, request: request)
|
96
93
|
end
|
97
94
|
# Credentials are valid, can call APIs
|
98
95
|
# ...
|
@@ -111,6 +108,8 @@ end
|
|
111
108
|
require 'googleauth'
|
112
109
|
require 'googleauth/stores/file_token_store'
|
113
110
|
|
111
|
+
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
|
112
|
+
|
114
113
|
scope = 'https://www.googleapis.com/auth/drive'
|
115
114
|
client_id = Google::Auth::ClientId.from_file('/path/to/client_secrets.json')
|
116
115
|
token_store = Google::Auth::Stores::FileTokenStore.new(
|
@@ -119,7 +118,7 @@ authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)
|
|
119
118
|
|
120
119
|
credentials = authorizer.get_credentials(user_id)
|
121
120
|
if credentials.nil?
|
122
|
-
url = authorizer.get_authorization_url(base_url:
|
121
|
+
url = authorizer.get_authorization_url(base_url: OOB_URI )
|
123
122
|
puts "Open #{url} in your browser and enter the resulting code:"
|
124
123
|
code = gets
|
125
124
|
credentials = authorizer.get_and_store_credentials_from_code(
|
@@ -129,6 +128,47 @@ end
|
|
129
128
|
# OK to use credentials
|
130
129
|
```
|
131
130
|
|
131
|
+
### Example (Service Account)
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
scope = 'https://www.googleapis.com/auth/androidpublisher'
|
135
|
+
|
136
|
+
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
|
137
|
+
json_key_io: File.open('/path/to/service_account_json_key.json'),
|
138
|
+
scope: scope)
|
139
|
+
|
140
|
+
authorizer.fetch_access_token!
|
141
|
+
```
|
142
|
+
|
143
|
+
### Example (Environment Variables)
|
144
|
+
|
145
|
+
```bash
|
146
|
+
export GOOGLE_ACCOUNT_TYPE=service_account
|
147
|
+
export GOOGLE_CLIENT_ID=000000000000000000000
|
148
|
+
export GOOGLE_CLIENT_EMAIL=xxxx@xxxx.iam.gserviceaccount.com
|
149
|
+
export GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
|
150
|
+
```
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
require 'googleauth'
|
154
|
+
require 'google/apis/drive_v3'
|
155
|
+
|
156
|
+
Drive = ::Google::Apis::DriveV3
|
157
|
+
drive = Drive::DriveService.new
|
158
|
+
|
159
|
+
# Auths with ENV vars:
|
160
|
+
# "GOOGLE_CLIENT_ID",
|
161
|
+
# "GOOGLE_CLIENT_EMAIL",
|
162
|
+
# "GOOGLE_ACCOUNT_TYPE",
|
163
|
+
# "GOOGLE_PRIVATE_KEY"
|
164
|
+
auth = ::Google::Auth::ServiceAccountCredentials
|
165
|
+
.make_creds(scope: 'https://www.googleapis.com/auth/drive')
|
166
|
+
drive.authorization = auth
|
167
|
+
|
168
|
+
list_files = drive.list_files()
|
169
|
+
|
170
|
+
```
|
171
|
+
|
132
172
|
### Storage
|
133
173
|
|
134
174
|
Authorizers require a storage instance to manage long term persistence of
|
@@ -138,15 +178,16 @@ access and refresh tokens. Two storage implementations are included:
|
|
138
178
|
* Google::Auth::Stores::RedisTokenStore
|
139
179
|
|
140
180
|
Custom storage implementations can also be used. See
|
141
|
-
[token_store.rb](
|
181
|
+
[token_store.rb](https://googleapis.dev/ruby/googleauth/latest/Google/Auth/TokenStore.html) for additional details.
|
182
|
+
|
183
|
+
## Supported Ruby Versions
|
142
184
|
|
143
|
-
|
185
|
+
This library requires Ruby 2.4 or later.
|
144
186
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
by Q2 2015.
|
187
|
+
In general, this library supports Ruby versions that are considered current and
|
188
|
+
supported by Ruby Core (that is, Ruby versions that are either in normal
|
189
|
+
maintenance or in security maintenance).
|
190
|
+
See https://www.ruby-lang.org/en/downloads/branches/ for further details.
|
150
191
|
|
151
192
|
## License
|
152
193
|
|
@@ -165,7 +206,6 @@ hesitate to
|
|
165
206
|
[ask questions](http://stackoverflow.com/questions/tagged/google-auth-library-ruby)
|
166
207
|
about the client or APIs on [StackOverflow](http://stackoverflow.com).
|
167
208
|
|
168
|
-
[
|
169
|
-
[
|
170
|
-
[
|
171
|
-
[copying]: https://github.com/google/google-auth-library-ruby/tree/master/COPYING
|
209
|
+
[application default credentials]: https://developers.google.com/accounts/docs/application-default-credentials
|
210
|
+
[contributing]: https://github.com/googleapis/google-auth-library-ruby/tree/master/.github/CONTRIBUTING.md
|
211
|
+
[copying]: https://github.com/googleapis/google-auth-library-ruby/tree/master/COPYING
|
data/Rakefile
CHANGED
@@ -1,15 +1,111 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require 'bundler/gem_tasks'
|
2
|
+
require "json"
|
3
|
+
require "bundler/gem_tasks"
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
task :ci do
|
6
|
+
header "Using Ruby - #{RUBY_VERSION}"
|
7
|
+
sh "bundle exec rubocop"
|
8
|
+
sh "bundle exec rspec"
|
9
|
+
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
+
task :release_gem, :tag do |_t, args|
|
12
|
+
tag = args[:tag]
|
13
|
+
raise "You must provide a tag to release." if tag.nil?
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
# Verify the tag format "vVERSION"
|
16
|
+
m = tag.match /v(?<version>\S*)/
|
17
|
+
raise "Tag #{tag} does not match the expected format." if m.nil?
|
14
18
|
|
15
|
-
|
19
|
+
version = m[:version]
|
20
|
+
raise "You must provide a version." if version.nil?
|
21
|
+
|
22
|
+
api_token = ENV["RUBYGEMS_API_TOKEN"]
|
23
|
+
|
24
|
+
require "gems"
|
25
|
+
if api_token
|
26
|
+
::Gems.configure do |config|
|
27
|
+
config.key = api_token
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Bundler.with_clean_env do
|
32
|
+
sh "rm -rf pkg"
|
33
|
+
sh "bundle update"
|
34
|
+
sh "bundle exec rake build"
|
35
|
+
end
|
36
|
+
|
37
|
+
path_to_be_pushed = "pkg/googleauth-#{version}.gem"
|
38
|
+
gem_was_published = nil
|
39
|
+
if File.file? path_to_be_pushed
|
40
|
+
begin
|
41
|
+
response = ::Gems.push File.new(path_to_be_pushed)
|
42
|
+
puts response
|
43
|
+
raise unless response.include? "Successfully registered gem:"
|
44
|
+
gem_was_published = true
|
45
|
+
puts "Successfully built and pushed googleauth for version #{version}"
|
46
|
+
rescue StandardError => e
|
47
|
+
gem_was_published = false
|
48
|
+
puts "Error while releasing googleauth version #{version}: #{e.message}"
|
49
|
+
end
|
50
|
+
else
|
51
|
+
raise "Cannot build googleauth for version #{version}"
|
52
|
+
end
|
53
|
+
|
54
|
+
Rake::Task["kokoro:publish_docs"].invoke if gem_was_published
|
55
|
+
end
|
56
|
+
|
57
|
+
namespace :kokoro do
|
58
|
+
task :load_env_vars do
|
59
|
+
service_account = "#{ENV['KOKORO_GFILE_DIR']}/service-account.json"
|
60
|
+
ENV["GOOGLE_APPLICATION_CREDENTIALS"] = service_account
|
61
|
+
filename = "#{ENV['KOKORO_GFILE_DIR']}/env_vars.json"
|
62
|
+
env_vars = JSON.parse File.read(filename)
|
63
|
+
env_vars.each { |k, v| ENV[k] = v }
|
64
|
+
end
|
65
|
+
|
66
|
+
task :presubmit do
|
67
|
+
Rake::Task["ci"].invoke
|
68
|
+
end
|
69
|
+
|
70
|
+
task :continuous do
|
71
|
+
Rake::Task["ci"].invoke
|
72
|
+
end
|
73
|
+
|
74
|
+
task :post do
|
75
|
+
require_relative "rakelib/link_checker.rb"
|
76
|
+
|
77
|
+
link_checker = LinkChecker.new
|
78
|
+
link_checker.run
|
79
|
+
exit link_checker.exit_status
|
80
|
+
end
|
81
|
+
|
82
|
+
task :nightly do
|
83
|
+
Rake::Task["ci"].invoke
|
84
|
+
end
|
85
|
+
|
86
|
+
task :release do
|
87
|
+
version = "0.1.0"
|
88
|
+
Bundler.with_clean_env do
|
89
|
+
version = `bundle exec gem list`
|
90
|
+
.split("\n").select { |line| line.include? "googleauth" }
|
91
|
+
.first.split("(").last.split(")").first || "0.1.0"
|
92
|
+
end
|
93
|
+
Rake::Task["kokoro:load_env_vars"].invoke
|
94
|
+
Rake::Task["release_gem"].invoke "v#{version}"
|
95
|
+
end
|
96
|
+
|
97
|
+
task :publish_docs do
|
98
|
+
require_relative "rakelib/devsite_builder.rb"
|
99
|
+
|
100
|
+
DevsiteBuilder.new(__dir__).publish
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def header str, token = "#"
|
105
|
+
line_length = str.length + 8
|
106
|
+
puts ""
|
107
|
+
puts token * line_length
|
108
|
+
puts "#{token * 3} #{str} #{token * 3}"
|
109
|
+
puts token * line_length
|
110
|
+
puts ""
|
111
|
+
end
|
data/googleauth.gemspec
CHANGED
@@ -1,35 +1,37 @@
|
|
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/google/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"
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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.12"
|
36
|
+
gem.add_development_dependency "yard", "~> 0.9"
|
35
37
|
end
|
@@ -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
|
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,51 @@
|
|
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
|
-
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
|
-
# is available
|
63
|
-
def on_gce?
|
62
|
+
# is available.
|
63
|
+
def on_gce? options = {}
|
64
|
+
# TODO: This should use google-cloud-env instead.
|
64
65
|
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
|
66
|
+
headers = { "Metadata-Flavor" => "Google" }
|
67
|
+
resp = c.get COMPUTE_CHECK_URI, nil, headers do |req|
|
68
|
+
req.options.timeout = 1.0
|
69
|
+
req.options.open_timeout = 0.1
|
75
70
|
end
|
76
71
|
return false unless resp.status == 200
|
77
|
-
|
78
|
-
return resp.headers['Metadata-Flavor'] == 'Google'
|
72
|
+
resp.headers["Metadata-Flavor"] == "Google"
|
79
73
|
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
80
|
-
|
74
|
+
false
|
81
75
|
end
|
82
76
|
|
83
77
|
memoize :on_gce?
|
@@ -85,19 +79,22 @@ END
|
|
85
79
|
|
86
80
|
# Overrides the super class method to change how access tokens are
|
87
81
|
# fetched.
|
88
|
-
def fetch_access_token
|
82
|
+
def fetch_access_token options = {}
|
89
83
|
c = options[:connection] || Faraday.default_connection
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
84
|
+
retry_with_error do
|
85
|
+
headers = { "Metadata-Flavor" => "Google" }
|
86
|
+
resp = c.get COMPUTE_AUTH_TOKEN_URI, nil, headers
|
87
|
+
case resp.status
|
88
|
+
when 200
|
89
|
+
Signet::OAuth2.parse_credentials(resp.body,
|
90
|
+
resp.headers["content-type"])
|
91
|
+
when 404
|
92
|
+
raise Signet::AuthorizationError, NO_METADATA_SERVER_ERROR
|
93
|
+
else
|
94
|
+
msg = "Unexpected error code #{resp.status}" \
|
95
|
+
"#{UNEXPECTED_ERROR_SUFFIX}"
|
96
|
+
raise Signet::AuthorizationError, msg
|
97
|
+
end
|
101
98
|
end
|
102
99
|
end
|
103
100
|
end
|