googleauth 0.8.1 → 0.9.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 +4 -4
- data/.kokoro/build.bat +9 -1
- data/.kokoro/continuous/windows.cfg +17 -1
- data/.kokoro/presubmit/windows.cfg +17 -1
- data/.kokoro/trampoline.bat +10 -0
- data/.rubocop.yml +37 -6
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -1
- data/README.md +1 -2
- data/googleauth.gemspec +1 -1
- data/lib/googleauth/application_default.rb +7 -7
- data/lib/googleauth/compute_engine.rb +10 -10
- data/lib/googleauth/credentials.rb +231 -46
- data/lib/googleauth/credentials_loader.rb +10 -7
- data/lib/googleauth/signet.rb +5 -4
- data/lib/googleauth/user_authorizer.rb +2 -2
- data/lib/googleauth/user_refresh.rb +1 -1
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +13 -8
- data/spec/googleauth/credentials_spec.rb +341 -155
- data/spec/googleauth/signet_spec.rb +31 -0
- data/spec/googleauth/web_user_authorizer_spec.rb +6 -0
- metadata +5 -4
- data/.kokoro/windows.sh +0 -4
@@ -49,7 +49,8 @@ module Google
|
|
49
49
|
PROJECT_ID_VAR = "GOOGLE_PROJECT_ID".freeze
|
50
50
|
GCLOUD_POSIX_COMMAND = "gcloud".freeze
|
51
51
|
GCLOUD_WINDOWS_COMMAND = "gcloud.cmd".freeze
|
52
|
-
GCLOUD_CONFIG_COMMAND =
|
52
|
+
GCLOUD_CONFIG_COMMAND =
|
53
|
+
"config config-helper --format json --verbosity none".freeze
|
53
54
|
|
54
55
|
CREDENTIALS_FILE_NAME = "application_default_credentials.json".freeze
|
55
56
|
NOT_FOUND_ERROR =
|
@@ -162,12 +163,11 @@ module Google
|
|
162
163
|
raise "#{SYSTEM_DEFAULT_ERROR}: #{e}"
|
163
164
|
end
|
164
165
|
|
165
|
-
module_function
|
166
|
-
|
167
166
|
# Issues warning if cloud sdk client id is used
|
168
167
|
def warn_if_cloud_sdk_credentials client_id
|
169
168
|
warn CLOUD_SDK_CREDENTIALS_WARNING if client_id == CLOUD_SDK_CLIENT_ID
|
170
169
|
end
|
170
|
+
module_function :warn_if_cloud_sdk_credentials
|
171
171
|
|
172
172
|
# Finds project_id from gcloud CLI configuration
|
173
173
|
def load_gcloud_project_id
|
@@ -179,6 +179,7 @@ module Google
|
|
179
179
|
rescue StandardError
|
180
180
|
nil
|
181
181
|
end
|
182
|
+
module_function :load_gcloud_project_id
|
182
183
|
|
183
184
|
private
|
184
185
|
|
@@ -192,13 +193,15 @@ module Google
|
|
192
193
|
end
|
193
194
|
|
194
195
|
def service_account_env_vars?
|
195
|
-
|
196
|
-
|
196
|
+
[PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR].all? do |key|
|
197
|
+
ENV[key] && !ENV[key].empty?
|
198
|
+
end
|
197
199
|
end
|
198
200
|
|
199
201
|
def authorized_user_env_vars?
|
200
|
-
|
201
|
-
|
202
|
+
[CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR].all? do |key|
|
203
|
+
ENV[key] && !ENV[key].empty?
|
204
|
+
end
|
202
205
|
end
|
203
206
|
end
|
204
207
|
end
|
data/lib/googleauth/signet.rb
CHANGED
@@ -76,7 +76,9 @@ module Signet
|
|
76
76
|
connection = build_default_connection
|
77
77
|
options = options.merge connection: connection if connection
|
78
78
|
end
|
79
|
-
info =
|
79
|
+
info = retry_with_error do
|
80
|
+
orig_fetch_access_token! options
|
81
|
+
end
|
80
82
|
notify_refresh_listeners
|
81
83
|
info
|
82
84
|
end
|
@@ -89,9 +91,8 @@ module Signet
|
|
89
91
|
end
|
90
92
|
|
91
93
|
def build_default_connection
|
92
|
-
|
93
|
-
|
94
|
-
elsif @connection_info.respond_to? :call
|
94
|
+
return nil unless defined?(@connection_info)
|
95
|
+
if @connection_info.respond_to? :call
|
95
96
|
@connection_info.call
|
96
97
|
else
|
97
98
|
@connection_info
|
@@ -129,8 +129,8 @@ module Google
|
|
129
129
|
data = MultiJson.load saved_token
|
130
130
|
|
131
131
|
if data.fetch("client_id", @client_id.id) != @client_id.id
|
132
|
-
raise
|
133
|
-
|
132
|
+
raise sprintf(MISMATCHED_CLIENT_ID_ERROR,
|
133
|
+
data["client_id"], @client_id.id)
|
134
134
|
end
|
135
135
|
|
136
136
|
credentials = UserRefreshCredentials.new(
|
@@ -79,7 +79,7 @@ module Google
|
|
79
79
|
# JSON key.
|
80
80
|
def self.read_json_key json_key_io
|
81
81
|
json_key = MultiJson.load json_key_io.read
|
82
|
-
wanted =
|
82
|
+
wanted = ["client_id", "client_secret", "refresh_token"]
|
83
83
|
wanted.each do |key|
|
84
84
|
raise "the json is missing the #{key} field" unless json_key.key? key
|
85
85
|
end
|
data/lib/googleauth/version.rb
CHANGED
@@ -154,6 +154,8 @@ module Google
|
|
154
154
|
# @param [String, Array<String>] scope
|
155
155
|
# Authorization scope to request. Overrides the instance scopes if
|
156
156
|
# not nil.
|
157
|
+
# @param [Hash] state
|
158
|
+
# Optional key-values to be returned to the oauth callback.
|
157
159
|
# @return [String]
|
158
160
|
# Authorization url
|
159
161
|
def get_authorization_url options = {}
|
@@ -162,22 +164,25 @@ module Google
|
|
162
164
|
raise NIL_REQUEST_ERROR if request.nil?
|
163
165
|
raise NIL_SESSION_ERROR if request.session.nil?
|
164
166
|
|
167
|
+
state = options[:state] || {}
|
168
|
+
|
165
169
|
redirect_to = options[:redirect_to] || request.url
|
166
170
|
request.session[XSRF_KEY] = SecureRandom.base64
|
167
|
-
options[:state] = MultiJson.dump(
|
168
|
-
|
169
|
-
|
170
|
-
)
|
171
|
+
options[:state] = MultiJson.dump(state.merge(
|
172
|
+
SESSION_ID_KEY => request.session[XSRF_KEY],
|
173
|
+
CURRENT_URI_KEY => redirect_to
|
174
|
+
))
|
171
175
|
options[:base_url] = request.url
|
172
176
|
super options
|
173
177
|
end
|
174
178
|
|
175
|
-
# Fetch stored credentials for the user.
|
179
|
+
# Fetch stored credentials for the user from the given request session.
|
176
180
|
#
|
177
181
|
# @param [String] user_id
|
178
182
|
# Unique ID of the user for loading/storing credentials.
|
179
183
|
# @param [Rack::Request] request
|
180
|
-
# Current request
|
184
|
+
# Current request. Optional. If omitted, this will attempt to fall back
|
185
|
+
# on the base class behavior of reading from the token store.
|
181
186
|
# @param [Array<String>, String] scope
|
182
187
|
# If specified, only returns credentials that have all the \
|
183
188
|
# requested scopes
|
@@ -186,8 +191,8 @@ module Google
|
|
186
191
|
# @raise [Signet::AuthorizationError]
|
187
192
|
# May raise an error if an authorization code is present in the session
|
188
193
|
# and exchange of the code fails
|
189
|
-
def get_credentials user_id, request, scope = nil
|
190
|
-
if request.session.key?
|
194
|
+
def get_credentials user_id, request = nil, scope = nil
|
195
|
+
if request && request.session.key?(CALLBACK_STATE_KEY)
|
191
196
|
# Note - in theory, no need to check required scope as this is
|
192
197
|
# expected to be called immediately after a return from authorization
|
193
198
|
state_json = request.session.delete CALLBACK_STATE_KEY
|
@@ -81,181 +81,367 @@ describe Google::Auth::Credentials, :private do
|
|
81
81
|
Google::Auth::Credentials.new default_keyfile_hash, scope: "http://example.com/scope"
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
84
|
+
describe "using CONSTANTS" do
|
85
|
+
it "can be subclassed to pass in other env paths" do
|
86
|
+
test_path_env_val = "/unknown/path/to/file.txt".freeze
|
87
|
+
test_json_env_val = JSON.generate default_keyfile_hash
|
88
|
+
|
89
|
+
ENV["TEST_PATH"] = test_path_env_val
|
90
|
+
ENV["TEST_JSON_VARS"] = test_json_env_val
|
91
|
+
|
92
|
+
class TestCredentials1 < Google::Auth::Credentials
|
93
|
+
TOKEN_CREDENTIAL_URI = "https://example.com/token".freeze
|
94
|
+
AUDIENCE = "https://example.com/audience".freeze
|
95
|
+
SCOPE = "http://example.com/scope".freeze
|
96
|
+
PATH_ENV_VARS = ["TEST_PATH"].freeze
|
97
|
+
JSON_ENV_VARS = ["TEST_JSON_VARS"].freeze
|
98
|
+
end
|
99
|
+
|
100
|
+
allow(::File).to receive(:file?).with(test_path_env_val) { false }
|
101
|
+
allow(::File).to receive(:file?).with(test_json_env_val) { false }
|
102
|
+
|
103
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
104
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
105
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
106
|
+
allow(mocked_signet).to receive(:client_id)
|
107
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
108
|
+
expect(options[:token_credential_uri]).to eq("https://example.com/token")
|
109
|
+
expect(options[:audience]).to eq("https://example.com/audience")
|
110
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
111
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
112
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
113
|
+
|
114
|
+
mocked_signet
|
115
|
+
end
|
116
|
+
|
117
|
+
creds = TestCredentials1.default
|
118
|
+
expect(creds).to be_a_kind_of(TestCredentials1)
|
119
|
+
expect(creds.client).to eq(mocked_signet)
|
120
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
96
121
|
end
|
97
122
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
123
|
+
it "subclasses can use PATH_ENV_VARS to get keyfile path" do
|
124
|
+
class TestCredentials2 < Google::Auth::Credentials
|
125
|
+
SCOPE = "http://example.com/scope".freeze
|
126
|
+
PATH_ENV_VARS = %w[PATH_ENV_DUMMY PATH_ENV_TEST].freeze
|
127
|
+
JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
|
128
|
+
DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
|
129
|
+
end
|
130
|
+
|
131
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
132
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
133
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
|
134
|
+
allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
|
135
|
+
allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
|
136
|
+
|
137
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
138
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
139
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
140
|
+
allow(mocked_signet).to receive(:client_id)
|
141
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
142
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
143
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
144
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
145
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
146
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
147
|
+
|
148
|
+
mocked_signet
|
149
|
+
end
|
150
|
+
|
151
|
+
creds = TestCredentials2.default
|
152
|
+
expect(creds).to be_a_kind_of(TestCredentials2)
|
153
|
+
expect(creds.client).to eq(mocked_signet)
|
154
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
112
155
|
end
|
113
156
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
157
|
+
it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
|
158
|
+
test_json_env_val = JSON.generate default_keyfile_hash
|
159
|
+
|
160
|
+
class TestCredentials3 < Google::Auth::Credentials
|
161
|
+
SCOPE = "http://example.com/scope".freeze
|
162
|
+
PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
|
163
|
+
JSON_ENV_VARS = %w[JSON_ENV_DUMMY JSON_ENV_TEST].freeze
|
164
|
+
DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
|
165
|
+
end
|
166
|
+
|
167
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
168
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
169
|
+
allow(::File).to receive(:file?).with(test_json_env_val) { false }
|
170
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
171
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
|
172
|
+
|
173
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
174
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
175
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
176
|
+
allow(mocked_signet).to receive(:client_id)
|
177
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
178
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
179
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
180
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
181
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
182
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
183
|
+
|
184
|
+
mocked_signet
|
185
|
+
end
|
186
|
+
|
187
|
+
creds = TestCredentials3.default
|
188
|
+
expect(creds).to be_a_kind_of(TestCredentials3)
|
189
|
+
expect(creds.client).to eq(mocked_signet)
|
190
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
126
191
|
end
|
127
192
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
mocked_signet
|
193
|
+
it "subclasses can use DEFAULT_PATHS to get keyfile path" do
|
194
|
+
class TestCredentials4 < Google::Auth::Credentials
|
195
|
+
SCOPE = "http://example.com/scope".freeze
|
196
|
+
PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
|
197
|
+
JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
|
198
|
+
DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
|
199
|
+
end
|
200
|
+
|
201
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
202
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
203
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
204
|
+
allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
|
205
|
+
allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
|
206
|
+
|
207
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
208
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
209
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
210
|
+
allow(mocked_signet).to receive(:client_id)
|
211
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
212
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
213
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
214
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
215
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
216
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
217
|
+
|
218
|
+
mocked_signet
|
219
|
+
end
|
220
|
+
|
221
|
+
creds = TestCredentials4.default
|
222
|
+
expect(creds).to be_a_kind_of(TestCredentials4)
|
223
|
+
expect(creds.client).to eq(mocked_signet)
|
224
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
146
225
|
end
|
147
226
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
227
|
+
it "subclasses that find no matches default to Google::Auth.get_application_default" do
|
228
|
+
class TestCredentials5 < Google::Auth::Credentials
|
229
|
+
SCOPE = "http://example.com/scope".freeze
|
230
|
+
PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
|
231
|
+
JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
|
232
|
+
DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
|
233
|
+
end
|
234
|
+
|
235
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
236
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
237
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
238
|
+
allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
|
239
|
+
|
240
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
241
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
242
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
243
|
+
allow(mocked_signet).to receive(:client_id)
|
244
|
+
allow(Google::Auth).to receive(:get_application_default) do |scope|
|
245
|
+
expect(scope).to eq([TestCredentials5::SCOPE])
|
246
|
+
|
247
|
+
# This should really be a Signet::OAuth2::Client object,
|
248
|
+
# but mocking is making that difficult, so return a valid hash instead.
|
249
|
+
default_keyfile_hash
|
250
|
+
end
|
251
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
252
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
253
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
254
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
255
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
256
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
257
|
+
|
258
|
+
mocked_signet
|
259
|
+
end
|
260
|
+
|
261
|
+
creds = TestCredentials5.default
|
262
|
+
expect(creds).to be_a_kind_of(TestCredentials5)
|
263
|
+
expect(creds.client).to eq(mocked_signet)
|
264
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
160
265
|
end
|
161
|
-
|
162
|
-
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
163
|
-
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
164
|
-
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
165
|
-
allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { JSON.generate default_keyfile_hash }
|
166
|
-
|
167
|
-
mocked_signet = double "Signet::OAuth2::Client"
|
168
|
-
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
169
|
-
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
170
|
-
allow(mocked_signet).to receive(:client_id)
|
171
|
-
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
172
|
-
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
173
|
-
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
174
|
-
expect(options[:scope]).to eq(["http://example.com/scope"])
|
175
|
-
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
176
|
-
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
177
|
-
|
178
|
-
mocked_signet
|
179
|
-
end
|
180
|
-
|
181
|
-
creds = TestCredentials.default
|
182
|
-
expect(creds).to be_a_kind_of(TestCredentials)
|
183
|
-
expect(creds.client).to eq(mocked_signet)
|
184
|
-
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
185
266
|
end
|
186
267
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
268
|
+
describe "using class methods" do
|
269
|
+
it "can be subclassed to pass in other env paths" do
|
270
|
+
test_path_env_val = "/unknown/path/to/file.txt".freeze
|
271
|
+
test_json_env_val = JSON.generate default_keyfile_hash
|
272
|
+
|
273
|
+
ENV["TEST_PATH"] = test_path_env_val
|
274
|
+
ENV["TEST_JSON_VARS"] = test_json_env_val
|
275
|
+
|
276
|
+
class TestCredentials11 < Google::Auth::Credentials
|
277
|
+
self.token_credential_uri = "https://example.com/token"
|
278
|
+
self.audience = "https://example.com/audience"
|
279
|
+
self.scope = "http://example.com/scope"
|
280
|
+
self.env_vars = ["TEST_PATH", "TEST_JSON_VARS"]
|
281
|
+
end
|
282
|
+
|
283
|
+
allow(::File).to receive(:file?).with(test_path_env_val) { false }
|
284
|
+
allow(::File).to receive(:file?).with(test_json_env_val) { false }
|
285
|
+
|
286
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
287
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
288
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
289
|
+
allow(mocked_signet).to receive(:client_id)
|
290
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
291
|
+
expect(options[:token_credential_uri]).to eq("https://example.com/token")
|
292
|
+
expect(options[:audience]).to eq("https://example.com/audience")
|
293
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
294
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
295
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
296
|
+
|
297
|
+
mocked_signet
|
298
|
+
end
|
299
|
+
|
300
|
+
creds = TestCredentials11.default
|
301
|
+
expect(creds).to be_a_kind_of(TestCredentials11)
|
302
|
+
expect(creds.client).to eq(mocked_signet)
|
303
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
193
304
|
end
|
194
305
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
306
|
+
it "subclasses can use PATH_ENV_VARS to get keyfile path" do
|
307
|
+
class TestCredentials12 < Google::Auth::Credentials
|
308
|
+
self.scope = "http://example.com/scope"
|
309
|
+
self.env_vars = %w[PATH_ENV_DUMMY PATH_ENV_TEST JSON_ENV_DUMMY]
|
310
|
+
self.paths = ["~/default/path/to/file.txt"]
|
311
|
+
end
|
312
|
+
|
313
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
314
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
315
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
|
316
|
+
allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
|
317
|
+
allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
|
318
|
+
|
319
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
320
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
321
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
322
|
+
allow(mocked_signet).to receive(:client_id)
|
323
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
324
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
325
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
326
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
327
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
328
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
329
|
+
|
330
|
+
mocked_signet
|
331
|
+
end
|
332
|
+
|
333
|
+
creds = TestCredentials12.default
|
334
|
+
expect(creds).to be_a_kind_of(TestCredentials12)
|
335
|
+
expect(creds.client).to eq(mocked_signet)
|
336
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
213
337
|
end
|
214
338
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
339
|
+
it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
|
340
|
+
test_json_env_val = JSON.generate default_keyfile_hash
|
341
|
+
|
342
|
+
class TestCredentials13 < Google::Auth::Credentials
|
343
|
+
self.scope = "http://example.com/scope"
|
344
|
+
self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY JSON_ENV_TEST]
|
345
|
+
self.paths = ["~/default/path/to/file.txt"]
|
346
|
+
end
|
347
|
+
|
348
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
349
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
350
|
+
allow(::File).to receive(:file?).with(test_json_env_val) { false }
|
351
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
352
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
|
353
|
+
|
354
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
355
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
356
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
357
|
+
allow(mocked_signet).to receive(:client_id)
|
358
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
359
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
360
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
361
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
362
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
363
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
364
|
+
|
365
|
+
mocked_signet
|
366
|
+
end
|
367
|
+
|
368
|
+
creds = TestCredentials13.default
|
369
|
+
expect(creds).to be_a_kind_of(TestCredentials13)
|
370
|
+
expect(creds.client).to eq(mocked_signet)
|
371
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
227
372
|
end
|
228
373
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
374
|
+
it "subclasses can use DEFAULT_PATHS to get keyfile path" do
|
375
|
+
class TestCredentials14 < Google::Auth::Credentials
|
376
|
+
self.scope = "http://example.com/scope"
|
377
|
+
self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
|
378
|
+
self.paths = ["~/default/path/to/file.txt"]
|
379
|
+
end
|
380
|
+
|
381
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
382
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
383
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
384
|
+
allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
|
385
|
+
allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
|
386
|
+
|
387
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
388
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
389
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
390
|
+
allow(mocked_signet).to receive(:client_id)
|
391
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
392
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
393
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
394
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
395
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
396
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
397
|
+
|
398
|
+
mocked_signet
|
399
|
+
end
|
400
|
+
|
401
|
+
creds = TestCredentials14.default
|
402
|
+
expect(creds).to be_a_kind_of(TestCredentials14)
|
403
|
+
expect(creds.client).to eq(mocked_signet)
|
404
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
244
405
|
end
|
245
|
-
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
246
|
-
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
247
|
-
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
248
|
-
expect(options[:scope]).to eq(["http://example.com/scope"])
|
249
|
-
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
250
|
-
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
251
406
|
|
252
|
-
|
407
|
+
it "subclasses that find no matches default to Google::Auth.get_application_default" do
|
408
|
+
class TestCredentials15 < Google::Auth::Credentials
|
409
|
+
self.scope = "http://example.com/scope"
|
410
|
+
self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
|
411
|
+
self.paths = ["~/default/path/to/file.txt"]
|
412
|
+
end
|
413
|
+
|
414
|
+
allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
|
415
|
+
allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
|
416
|
+
allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
|
417
|
+
allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
|
418
|
+
|
419
|
+
mocked_signet = double "Signet::OAuth2::Client"
|
420
|
+
allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
|
421
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
422
|
+
allow(mocked_signet).to receive(:client_id)
|
423
|
+
allow(Google::Auth).to receive(:get_application_default) do |scope|
|
424
|
+
expect(scope).to eq(TestCredentials15.scope)
|
425
|
+
|
426
|
+
# This should really be a Signet::OAuth2::Client object,
|
427
|
+
# but mocking is making that difficult, so return a valid hash instead.
|
428
|
+
default_keyfile_hash
|
429
|
+
end
|
430
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
431
|
+
expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
|
432
|
+
expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
|
433
|
+
expect(options[:scope]).to eq(["http://example.com/scope"])
|
434
|
+
expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
|
435
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
436
|
+
|
437
|
+
mocked_signet
|
438
|
+
end
|
439
|
+
|
440
|
+
creds = TestCredentials15.default
|
441
|
+
expect(creds).to be_a_kind_of(TestCredentials15)
|
442
|
+
expect(creds.client).to eq(mocked_signet)
|
443
|
+
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
253
444
|
end
|
254
|
-
|
255
|
-
creds = TestCredentials.default
|
256
|
-
expect(creds).to be_a_kind_of(TestCredentials)
|
257
|
-
expect(creds.client).to eq(mocked_signet)
|
258
|
-
expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
|
259
445
|
end
|
260
446
|
|
261
447
|
it "warns when cloud sdk credentials are used" do
|