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.
@@ -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 = "config config-helper --format json".freeze
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
- ([PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR] - ENV.keys).empty? &&
196
- !ENV.to_h.fetch_values(PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR).join(" ").empty?
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
- ([CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR] - ENV.keys).empty? &&
201
- !ENV.to_h.fetch_values(CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR).join(" ").empty?
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
@@ -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 = orig_fetch_access_token! options
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
- if !defined?(@connection_info)
93
- nil
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 format(MISMATCHED_CLIENT_ID_ERROR,
133
- data["client_id"], @client_id.id)
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 = %w[client_id client_secret refresh_token]
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
@@ -31,6 +31,6 @@ module Google
31
31
  # Module Auth provides classes that provide Google-specific authorization
32
32
  # used to access Google APIs.
33
33
  module Auth
34
- VERSION = "0.8.1".freeze
34
+ VERSION = "0.9.0".freeze
35
35
  end
36
36
  end
@@ -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
- SESSION_ID_KEY => request.session[XSRF_KEY],
169
- CURRENT_URI_KEY => redirect_to
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? CALLBACK_STATE_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
- it "can be subclassed to pass in other env paths" do
85
- TEST_PATH_ENV_VAR = "TEST_PATH".freeze
86
- TEST_PATH_ENV_VAL = "/unknown/path/to/file.txt".freeze
87
- TEST_JSON_ENV_VAR = "TEST_JSON_VARS".freeze
88
-
89
- ENV[TEST_PATH_ENV_VAR] = TEST_PATH_ENV_VAL
90
- ENV[TEST_JSON_ENV_VAR] = JSON.generate default_keyfile_hash
91
-
92
- class TestCredentials < Google::Auth::Credentials
93
- SCOPE = "http://example.com/scope".freeze
94
- PATH_ENV_VARS = [TEST_PATH_ENV_VAR].freeze
95
- JSON_ENV_VARS = [TEST_JSON_ENV_VAR].freeze
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
- allow(::File).to receive(:file?).with(TEST_PATH_ENV_VAL) { false }
99
-
100
- mocked_signet = double "Signet::OAuth2::Client"
101
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
102
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
103
- allow(mocked_signet).to receive(:client_id)
104
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
105
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
106
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
107
- expect(options[:scope]).to eq(["http://example.com/scope"])
108
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
109
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
110
-
111
- mocked_signet
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
- creds = TestCredentials.default
115
- expect(creds).to be_a_kind_of(TestCredentials)
116
- expect(creds.client).to eq(mocked_signet)
117
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
118
- end
119
-
120
- it "subclasses can use PATH_ENV_VARS to get keyfile path" do
121
- class TestCredentials < Google::Auth::Credentials
122
- SCOPE = "http://example.com/scope".freeze
123
- PATH_ENV_VARS = %w[PATH_ENV_DUMMY PATH_ENV_TEST].freeze
124
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
125
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
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
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
129
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
130
- allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
131
- allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
132
- allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
133
-
134
- mocked_signet = double "Signet::OAuth2::Client"
135
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
136
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
137
- allow(mocked_signet).to receive(:client_id)
138
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
139
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
140
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
141
- expect(options[:scope]).to eq(["http://example.com/scope"])
142
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
143
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
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
- creds = TestCredentials.default
149
- expect(creds).to be_a_kind_of(TestCredentials)
150
- expect(creds.client).to eq(mocked_signet)
151
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
152
- end
153
-
154
- it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
155
- class TestCredentials < Google::Auth::Credentials
156
- SCOPE = "http://example.com/scope".freeze
157
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
158
- JSON_ENV_VARS = %w[JSON_ENV_DUMMY JSON_ENV_TEST].freeze
159
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
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
- it "subclasses can use DEFAULT_PATHS to get keyfile path" do
188
- class TestCredentials < Google::Auth::Credentials
189
- SCOPE = "http://example.com/scope".freeze
190
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
191
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
192
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
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
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
196
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
197
- allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
198
- allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
199
- allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
200
-
201
- mocked_signet = double "Signet::OAuth2::Client"
202
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
203
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
204
- allow(mocked_signet).to receive(:client_id)
205
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
206
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
207
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
208
- expect(options[:scope]).to eq(["http://example.com/scope"])
209
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
210
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
211
-
212
- mocked_signet
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
- creds = TestCredentials.default
216
- expect(creds).to be_a_kind_of(TestCredentials)
217
- expect(creds.client).to eq(mocked_signet)
218
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
219
- end
220
-
221
- it "subclasses that find no matches default to Google::Auth.get_application_default" do
222
- class TestCredentials < Google::Auth::Credentials
223
- SCOPE = "http://example.com/scope".freeze
224
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
225
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
226
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
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
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
230
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
231
- allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
232
- allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
233
-
234
- mocked_signet = double "Signet::OAuth2::Client"
235
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
236
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
237
- allow(mocked_signet).to receive(:client_id)
238
- allow(Google::Auth).to receive(:get_application_default) do |scope|
239
- expect(scope).to eq(TestCredentials::SCOPE)
240
-
241
- # This should really be a Signet::OAuth2::Client object,
242
- # but mocking is making that difficult, so return a valid hash instead.
243
- default_keyfile_hash
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
- mocked_signet
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