googleauth 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|